diff options
Diffstat (limited to 'source/blender/editors')
84 files changed, 2017 insertions, 1746 deletions
diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c index 06a0077df9b..329bc2b46eb 100644 --- a/source/blender/editors/animation/anim_draw.c +++ b/source/blender/editors/animation/anim_draw.c @@ -329,6 +329,121 @@ short ANIM_get_normalization_flags(bAnimContext *ac) return 0; } +static void fcurve_scene_coord_range_get(Scene *scene, + FCurve *fcu, + float *r_min_coord, + float *r_max_coord) +{ + float min_coord = FLT_MAX; + float max_coord = -FLT_MAX; + const bool use_preview_only = PRVRANGEON; + + if (fcu->bezt || fcu->fpt) { + int start = 0; + int end = fcu->totvert; + + if (use_preview_only) { + start = scene->r.psfra; + end = min_ii(scene->r.pefra + 1, fcu->totvert); + } + + if (fcu->bezt) { + const BezTriple *bezt = fcu->bezt + start; + for (int i = start; i < end; i++, bezt++) { + + if (i == 0) { + /* We ignore extrapolation flags and handle here, and use the + * control point position only. so we normalize "interesting" + * part of the curve. + * + * Here we handle left extrapolation. + */ + max_coord = max_ff(max_coord, bezt->vec[1][1]); + min_coord = min_ff(min_coord, bezt->vec[1][1]); + } + else { + const BezTriple *prev_bezt = bezt - 1; + if (!ELEM(prev_bezt->ipo, BEZT_IPO_BEZ, BEZT_IPO_BACK, BEZT_IPO_ELASTIC)) { + /* The points on the curve will lie inside the start and end points. + * Calculate min/max using both previous and current CV. + */ + max_coord = max_ff(max_coord, bezt->vec[1][1]); + min_coord = min_ff(min_coord, bezt->vec[1][1]); + max_coord = max_ff(max_coord, prev_bezt->vec[1][1]); + min_coord = min_ff(min_coord, prev_bezt->vec[1][1]); + } + else { + const int resol = fcu->driver ? + 32 : + min_ii((int)(5.0f * len_v2v2(bezt->vec[1], prev_bezt->vec[1])), + 32); + if (resol < 2) { + max_coord = max_ff(max_coord, prev_bezt->vec[1][1]); + min_coord = min_ff(min_coord, prev_bezt->vec[1][1]); + } + else { + if (!ELEM(prev_bezt->ipo, BEZT_IPO_BACK, BEZT_IPO_ELASTIC)) { + /* Calculate min/max using bezier forward differencing. */ + float data[120]; + float v1[2], v2[2], v3[2], v4[2]; + + v1[0] = prev_bezt->vec[1][0]; + v1[1] = prev_bezt->vec[1][1]; + v2[0] = prev_bezt->vec[2][0]; + v2[1] = prev_bezt->vec[2][1]; + + v3[0] = bezt->vec[0][0]; + v3[1] = bezt->vec[0][1]; + v4[0] = bezt->vec[1][0]; + v4[1] = bezt->vec[1][1]; + + BKE_fcurve_correct_bezpart(v1, v2, v3, v4); + + BKE_curve_forward_diff_bezier( + v1[0], v2[0], v3[0], v4[0], data, resol, sizeof(float[3])); + BKE_curve_forward_diff_bezier( + v1[1], v2[1], v3[1], v4[1], data + 1, resol, sizeof(float[3])); + + for (int j = 0; j <= resol; ++j) { + const float *fp = &data[j * 3]; + max_coord = max_ff(max_coord, fp[1]); + min_coord = min_ff(min_coord, fp[1]); + } + } + else { + /* Calculate min/max using full fcurve evaluation. + * [slower than bezier forward differencing but evaluates Back/Elastic + * interpolation as well]. */ + float step_size = (bezt->vec[1][0] - prev_bezt->vec[1][0]) / resol; + for (int j = 0; j <= resol; j++) { + float eval_time = prev_bezt->vec[1][0] + step_size * j; + float eval_value = evaluate_fcurve_only_curve(fcu, eval_time); + max_coord = max_ff(max_coord, eval_value); + min_coord = min_ff(min_coord, eval_value); + } + } + } + } + } + } + } + else if (fcu->fpt) { + const FPoint *fpt = fcu->fpt + start; + for (int i = start; i < end; ++i, ++fpt) { + min_coord = min_ff(min_coord, fpt->vec[1]); + max_coord = max_ff(max_coord, fpt->vec[1]); + } + } + } + + if (r_min_coord) { + *r_min_coord = min_coord; + } + if (r_max_coord) { + *r_max_coord = max_coord; + } +} + static float normalization_factor_get(Scene *scene, FCurve *fcu, short flag, float *r_offset) { float factor = 1.0f, offset = 0.0f; @@ -366,112 +481,23 @@ static float normalization_factor_get(Scene *scene, FCurve *fcu, short flag, flo } fcu->prev_norm_factor = 1.0f; - if (fcu->bezt) { - const bool use_preview_only = PRVRANGEON; - const BezTriple *bezt; - int i; - float max_coord = -FLT_MAX; - float min_coord = FLT_MAX; - float range; - - if (fcu->totvert < 1) { - return 1.0f; - } - - for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) { - if (use_preview_only && !IN_RANGE_INCL(bezt->vec[1][0], scene->r.psfra, scene->r.pefra)) { - continue; - } - - if (i == 0) { - /* We ignore extrapolation flags and handle here, and use the - * control point position only. so we normalize "interesting" - * part of the curve. - * - * Here we handle left extrapolation. - */ - max_coord = max_ff(max_coord, bezt->vec[1][1]); - min_coord = min_ff(min_coord, bezt->vec[1][1]); - } - else { - const BezTriple *prev_bezt = bezt - 1; - if (!ELEM(prev_bezt->ipo, BEZT_IPO_BEZ, BEZT_IPO_BACK, BEZT_IPO_ELASTIC)) { - /* The points on the curve will lie inside the start and end points. - * Calculate min/max using both previous and current CV. - */ - max_coord = max_ff(max_coord, bezt->vec[1][1]); - min_coord = min_ff(min_coord, bezt->vec[1][1]); - max_coord = max_ff(max_coord, prev_bezt->vec[1][1]); - min_coord = min_ff(min_coord, prev_bezt->vec[1][1]); - } - else { - const int resol = fcu->driver ? - 32 : - min_ii((int)(5.0f * len_v2v2(bezt->vec[1], prev_bezt->vec[1])), - 32); - if (resol < 2) { - max_coord = max_ff(max_coord, prev_bezt->vec[1][1]); - min_coord = min_ff(min_coord, prev_bezt->vec[1][1]); - } - else { - if (!ELEM(prev_bezt->ipo, BEZT_IPO_BACK, BEZT_IPO_ELASTIC)) { - /* Calculate min/max using bezier forward differencing. */ - float data[120]; - float v1[2], v2[2], v3[2], v4[2]; - - v1[0] = prev_bezt->vec[1][0]; - v1[1] = prev_bezt->vec[1][1]; - v2[0] = prev_bezt->vec[2][0]; - v2[1] = prev_bezt->vec[2][1]; - - v3[0] = bezt->vec[0][0]; - v3[1] = bezt->vec[0][1]; - v4[0] = bezt->vec[1][0]; - v4[1] = bezt->vec[1][1]; - - BKE_fcurve_correct_bezpart(v1, v2, v3, v4); - - BKE_curve_forward_diff_bezier( - v1[0], v2[0], v3[0], v4[0], data, resol, sizeof(float[3])); - BKE_curve_forward_diff_bezier( - v1[1], v2[1], v3[1], v4[1], data + 1, resol, sizeof(float[3])); - - for (int j = 0; j <= resol; ++j) { - const float *fp = &data[j * 3]; - max_coord = max_ff(max_coord, fp[1]); - min_coord = min_ff(min_coord, fp[1]); - } - } - else { - /* Calculate min/max using full fcurve evaluation. - * [slower than bezier forward differencing but evaluates Back/Elastic interpolation - * as well]. */ - float step_size = (bezt->vec[1][0] - prev_bezt->vec[1][0]) / resol; - for (int j = 0; j <= resol; j++) { - float eval_time = prev_bezt->vec[1][0] + step_size * j; - float eval_value = evaluate_fcurve_only_curve(fcu, eval_time); - max_coord = max_ff(max_coord, eval_value); - min_coord = min_ff(min_coord, eval_value); - } - } - } - } - } - } + float max_coord = -FLT_MAX; + float min_coord = FLT_MAX; + fcurve_scene_coord_range_get(scene, fcu, &min_coord, &max_coord); - if (max_coord > min_coord) { - range = max_coord - min_coord; - if (range > FLT_EPSILON) { - factor = 2.0f / range; - } - offset = -min_coord - range / 2.0f; - } - else if (max_coord == min_coord) { - factor = 1.0f; - offset = -min_coord; + if (max_coord > min_coord) { + const float range = max_coord - min_coord; + if (range > FLT_EPSILON) { + factor = 2.0f / range; } + offset = -min_coord - range / 2.0f; + } + else if (max_coord == min_coord) { + factor = 1.0f; + offset = -min_coord; } + BLI_assert(factor != 0.0f); if (r_offset) { *r_offset = offset; diff --git a/source/blender/editors/asset/intern/asset_handle.cc b/source/blender/editors/asset/intern/asset_handle.cc index 00fffd595c0..0b2cd352d77 100644 --- a/source/blender/editors/asset/intern/asset_handle.cc +++ b/source/blender/editors/asset/intern/asset_handle.cc @@ -8,6 +8,9 @@ #include "DNA_space_types.h" +#include "BKE_asset.h" +#include "BKE_asset_representation.hh" + #include "BLO_readfile.h" #include "ED_asset_handle.h" @@ -17,12 +20,12 @@ const char *ED_asset_handle_get_name(const AssetHandle *asset) { - return asset->file_data->name; + return BKE_asset_representation_name_get(asset->file_data->asset); } -AssetMetaData *ED_asset_handle_get_metadata(const AssetHandle *asset) +AssetMetaData *ED_asset_handle_get_metadata(const AssetHandle *asset_handle) { - return asset->file_data->asset_data; + return BKE_asset_representation_metadata_get(asset_handle->file_data->asset); } ID *ED_asset_handle_get_local_id(const AssetHandle *asset) diff --git a/source/blender/editors/asset/intern/asset_temp_id_consumer.cc b/source/blender/editors/asset/intern/asset_temp_id_consumer.cc index 376454d62b6..d1fd48d966c 100644 --- a/source/blender/editors/asset/intern/asset_temp_id_consumer.cc +++ b/source/blender/editors/asset/intern/asset_temp_id_consumer.cc @@ -72,7 +72,7 @@ AssetTempIDConsumer *ED_asset_temp_id_consumer_create(const AssetHandle *handle) if (!handle) { return nullptr; } - BLI_assert(handle->file_data->asset_data != nullptr); + BLI_assert(handle->file_data->asset != nullptr); return reinterpret_cast<AssetTempIDConsumer *>( MEM_new<AssetTemporaryIDConsumer>(__func__, *handle)); } diff --git a/source/blender/editors/geometry/geometry_attributes.cc b/source/blender/editors/geometry/geometry_attributes.cc index 73b5cab1b25..7f163da493b 100644 --- a/source/blender/editors/geometry/geometry_attributes.cc +++ b/source/blender/editors/geometry/geometry_attributes.cc @@ -98,7 +98,7 @@ static int geometry_attribute_add_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - BKE_id_attributes_active_set(id, layer); + BKE_id_attributes_active_set(id, layer->name); DEG_id_tag_update(id, ID_RECALC_GEOMETRY); WM_main_add_notifier(NC_GEOM | ND_DATA, id); @@ -275,15 +275,14 @@ static int geometry_attribute_convert_exec(bContext *C, wmOperator *op) { Object *ob = ED_object_context(C); ID *ob_data = static_cast<ID *>(ob->data); - const CustomDataLayer *layer = BKE_id_attributes_active_get(ob_data); - const std::string name = layer->name; - + CustomDataLayer *layer = BKE_id_attributes_active_get(ob_data); const ConvertAttributeMode mode = static_cast<ConvertAttributeMode>( RNA_enum_get(op->ptr, "mode")); - Mesh *mesh = reinterpret_cast<Mesh *>(ob_data); bke::MutableAttributeAccessor attributes = mesh->attributes_for_write(); + const std::string name = layer->name; + /* General conversion steps are always the same: * 1. Convert old data to right domain and data type. * 2. Copy the data into a new array so that it does not depend on the old attribute anymore. @@ -291,21 +290,13 @@ static int geometry_attribute_convert_exec(bContext *C, wmOperator *op) * 4. Create a new attribute based on the previously copied data. */ switch (mode) { case ConvertAttributeMode::Generic: { - const eAttrDomain dst_domain = static_cast<eAttrDomain>(RNA_enum_get(op->ptr, "domain")); - const eCustomDataType dst_type = static_cast<eCustomDataType>( - RNA_enum_get(op->ptr, "data_type")); - - if (ELEM(dst_type, CD_PROP_STRING)) { - BKE_report(op->reports, RPT_ERROR, "Cannot convert to the selected type"); + if (!ED_geometry_attribute_convert(mesh, + name.c_str(), + eCustomDataType(RNA_enum_get(op->ptr, "data_type")), + eAttrDomain(RNA_enum_get(op->ptr, "domain")), + op->reports)) { return OPERATOR_CANCELLED; } - - GVArray src_varray = attributes.lookup_or_default(name, dst_domain, dst_type); - const CPPType &cpp_type = src_varray.type(); - void *new_data = MEM_malloc_arrayN(src_varray.size(), cpp_type.size(), __func__); - src_varray.materialize_to_uninitialized(new_data); - attributes.remove(name); - attributes.add(name, dst_domain, dst_type, blender::bke::AttributeInitMoveArray(new_data)); break; } case ConvertAttributeMode::UVMap: { @@ -319,6 +310,10 @@ static int geometry_attribute_convert_exec(bContext *C, wmOperator *op) attributes.remove(name); CustomData_add_layer_named( &mesh->ldata, CD_MLOOPUV, CD_ASSIGN, dst_uvs, mesh->totloop, name.c_str()); + int *active_index = BKE_id_attributes_active_index_p(&mesh->id); + if (*active_index > 0) { + *active_index -= 1; + } break; } case ConvertAttributeMode::VertexGroup: { @@ -337,18 +332,16 @@ static int geometry_attribute_convert_exec(bContext *C, wmOperator *op) BKE_defvert_add_index_notest(dverts + i, defgroup_index, weight); } } + int *active_index = BKE_id_attributes_active_index_p(&mesh->id); + if (*active_index > 0) { + *active_index -= 1; + } break; } } - int *active_index = BKE_id_attributes_active_index_p(&mesh->id); - if (*active_index > 0) { - *active_index -= 1; - } - DEG_id_tag_update(&mesh->id, ID_RECALC_GEOMETRY); WM_main_add_notifier(NC_GEOM | ND_DATA, &mesh->id); - return OPERATOR_FINISHED; } @@ -590,6 +583,79 @@ static int geometry_attribute_convert_invoke(bContext *C, return WM_operator_props_dialog_popup(C, op, 300); } +static bool geometry_color_attribute_convert_poll(bContext *C) +{ + if (!geometry_attributes_poll(C)) { + return false; + } + + Object *ob = ED_object_context(C); + ID *id = static_cast<ID *>(ob->data); + if (GS(id->name) != ID_ME) { + return false; + } + CustomDataLayer *layer = BKE_id_attributes_active_color_get(id); + if (layer == nullptr) { + return false; + } + return true; +} + +static int geometry_color_attribute_convert_exec(bContext *C, wmOperator *op) +{ + Object *ob = ED_object_context(C); + ID *ob_data = static_cast<ID *>(ob->data); + CustomDataLayer *layer = BKE_id_attributes_active_color_get(ob_data); + ED_geometry_attribute_convert(static_cast<Mesh *>(ob->data), + layer->name, + eCustomDataType(RNA_enum_get(op->ptr, "data_type")), + eAttrDomain(RNA_enum_get(op->ptr, "domain")), + op->reports); + return OPERATOR_FINISHED; +} + +static void geometry_color_attribute_convert_ui(bContext *UNUSED(C), wmOperator *op) +{ + uiLayout *layout = op->layout; + uiLayoutSetPropSep(layout, true); + uiLayoutSetPropDecorate(layout, false); + + uiItemR(layout, op->ptr, "domain", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); + uiItemR(layout, op->ptr, "data_type", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); +} + +void GEOMETRY_OT_color_attribute_convert(wmOperatorType *ot) +{ + ot->name = "Convert Color Attribute"; + ot->description = "Change how the color attribute is stored"; + ot->idname = "GEOMETRY_OT_color_attribute_convert"; + + ot->invoke = geometry_attribute_convert_invoke; + ot->exec = geometry_color_attribute_convert_exec; + ot->poll = geometry_color_attribute_convert_poll; + ot->ui = geometry_color_attribute_convert_ui; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + PropertyRNA *prop; + + prop = RNA_def_enum(ot->srna, + "domain", + rna_enum_color_attribute_domain_items, + ATTR_DOMAIN_POINT, + "Domain", + "Type of element that attribute is stored on"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + prop = RNA_def_enum(ot->srna, + "data_type", + rna_enum_color_attribute_type_items, + CD_PROP_COLOR, + "Data Type", + "Type of data stored in attribute"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); +} + void GEOMETRY_OT_attribute_convert(wmOperatorType *ot) { ot->name = "Convert Attribute"; @@ -628,37 +694,31 @@ void GEOMETRY_OT_attribute_convert(wmOperatorType *ot) } // namespace blender::ed::geometry -using blender::CPPType; -using blender::GVArray; - bool ED_geometry_attribute_convert(Mesh *mesh, - const char *layer_name, - eCustomDataType old_type, - eAttrDomain old_domain, - eCustomDataType new_type, - eAttrDomain new_domain) + const char *name, + const eCustomDataType dst_type, + const eAttrDomain dst_domain, + ReportList *reports) { - CustomDataLayer *layer = BKE_id_attribute_find(&mesh->id, layer_name, old_type, old_domain); - const std::string name = layer->name; - - if (!layer) { + using namespace blender; + bke::MutableAttributeAccessor attributes = mesh->attributes_for_write(); + BLI_assert(mesh->attributes().contains(name)); + BLI_assert(mesh->edit_mesh == nullptr); + if (ELEM(dst_type, CD_PROP_STRING)) { + if (reports) { + BKE_report(reports, RPT_ERROR, "Cannot convert to the selected type"); + } return false; } - blender::bke::MutableAttributeAccessor attributes = mesh->attributes_for_write(); + const std::string name_copy = name; + const GVArray varray = attributes.lookup_or_default(name_copy, dst_domain, dst_type); - GVArray src_varray = attributes.lookup_or_default(name, new_domain, new_type); - - const CPPType &cpp_type = src_varray.type(); - void *new_data = MEM_malloc_arrayN(src_varray.size(), cpp_type.size(), __func__); - src_varray.materialize_to_uninitialized(new_data); - attributes.remove(name); - attributes.add(name, new_domain, new_type, blender::bke::AttributeInitMoveArray(new_data)); - - int *active_index = BKE_id_attributes_active_index_p(&mesh->id); - if (*active_index > 0) { - *active_index -= 1; - } + const CPPType &cpp_type = varray.type(); + void *new_data = MEM_malloc_arrayN(varray.size(), cpp_type.size(), __func__); + varray.materialize_to_uninitialized(new_data); + attributes.remove(name_copy); + attributes.add(name_copy, dst_domain, dst_type, bke::AttributeInitMoveArray(new_data)); return true; } diff --git a/source/blender/editors/geometry/geometry_intern.hh b/source/blender/editors/geometry/geometry_intern.hh index a1000a5d01f..0ae63d07c6d 100644 --- a/source/blender/editors/geometry/geometry_intern.hh +++ b/source/blender/editors/geometry/geometry_intern.hh @@ -19,5 +19,6 @@ void GEOMETRY_OT_color_attribute_remove(struct wmOperatorType *ot); void GEOMETRY_OT_color_attribute_render_set(struct wmOperatorType *ot); void GEOMETRY_OT_color_attribute_duplicate(struct wmOperatorType *ot); void GEOMETRY_OT_attribute_convert(struct wmOperatorType *ot); +void GEOMETRY_OT_color_attribute_convert(struct wmOperatorType *ot); } // namespace blender::ed::geometry diff --git a/source/blender/editors/geometry/geometry_ops.cc b/source/blender/editors/geometry/geometry_ops.cc index acac757ecf1..79a0468f51a 100644 --- a/source/blender/editors/geometry/geometry_ops.cc +++ b/source/blender/editors/geometry/geometry_ops.cc @@ -24,4 +24,5 @@ void ED_operatortypes_geometry(void) WM_operatortype_append(GEOMETRY_OT_color_attribute_render_set); WM_operatortype_append(GEOMETRY_OT_color_attribute_duplicate); WM_operatortype_append(GEOMETRY_OT_attribute_convert); + WM_operatortype_append(GEOMETRY_OT_color_attribute_convert); } diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c index 37c1524c2ff..ab3edfdd4fa 100644 --- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c +++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c @@ -68,6 +68,8 @@ #include "gpencil_intern.h" +#define SEARCH_RADIUS_PIXEL 20 + /* ************************************************ */ /* General Brush Editing Context */ @@ -78,6 +80,7 @@ typedef struct tGP_BrushEditData { Main *bmain; Scene *scene; Object *object; + Object *ob_eval; ScrArea *area; ARegion *region; @@ -1181,6 +1184,8 @@ static bool gpencil_sculpt_brush_init(bContext *C, wmOperator *op) } /* Check if some modifier can transform the stroke. */ gso->is_transformed = BKE_gpencil_has_transform_modifiers(ob); + + gso->ob_eval = (Object *)DEG_get_evaluated_id(gso->depsgraph, &ob->id); } else { unit_m4(gso->inv_mat); @@ -1196,9 +1201,13 @@ static bool gpencil_sculpt_brush_init(bContext *C, wmOperator *op) gso->brush = brush; BKE_curvemapping_init(gso->brush->curve); - if (brush->gpencil_settings->sculpt_mode_flag & - (GP_SCULPT_FLAGMODE_AUTOMASK_STROKE | GP_SCULPT_FLAGMODE_AUTOMASK_LAYER | - GP_SCULPT_FLAGMODE_AUTOMASK_MATERIAL)) { + const bool is_automasking = (ts->gp_sculpt.flag & + (GP_SCULPT_SETT_FLAG_AUTOMASK_STROKE | + GP_SCULPT_SETT_FLAG_AUTOMASK_LAYER_STROKE | + GP_SCULPT_SETT_FLAG_AUTOMASK_MATERIAL_STROKE | + GP_SCULPT_SETT_FLAG_AUTOMASK_LAYER_ACTIVE | + GP_SCULPT_SETT_FLAG_AUTOMASK_MATERIAL_ACTIVE)) != 0; + if (is_automasking) { gso->automasking_strokes = BLI_ghash_ptr_new(__func__); } else { @@ -1604,13 +1613,16 @@ static bool gpencil_sculpt_brush_do_frame(bContext *C, bGPdata *gpd = ob->data; const char tool = gso->brush->gpencil_sculpt_tool; GP_SpaceConversion *gsc = &gso->gsc; + ToolSettings *ts = gso->scene->toolsettings; Brush *brush = gso->brush; const int radius = (brush->flag & GP_BRUSH_USE_PRESSURE) ? gso->brush->size * gso->pressure : gso->brush->size; - const bool is_automasking = (brush->gpencil_settings->sculpt_mode_flag & - (GP_SCULPT_FLAGMODE_AUTOMASK_STROKE | - GP_SCULPT_FLAGMODE_AUTOMASK_LAYER | - GP_SCULPT_FLAGMODE_AUTOMASK_MATERIAL)) != 0; + const bool is_automasking = (ts->gp_sculpt.flag & + (GP_SCULPT_SETT_FLAG_AUTOMASK_STROKE | + GP_SCULPT_SETT_FLAG_AUTOMASK_LAYER_STROKE | + GP_SCULPT_SETT_FLAG_AUTOMASK_MATERIAL_STROKE | + GP_SCULPT_SETT_FLAG_AUTOMASK_LAYER_ACTIVE | + GP_SCULPT_SETT_FLAG_AUTOMASK_MATERIAL_ACTIVE)) != 0; /* Calc bound box matrix. */ float bound_mat[4][4]; BKE_gpencil_layer_transform_matrix_get(gso->depsgraph, gso->object, gpl, bound_mat); @@ -1743,27 +1755,111 @@ static bool gpencil_sculpt_brush_do_frame(bContext *C, return changed; } +/* Find the stroke nearer to the brush. */ +static void get_nearest_stroke_to_brush(tGP_BrushEditData *gso, + int mval_i[2], + bGPDlayer **r_gpl, + bGPDstroke **r_gps) +{ + const int radius = SEARCH_RADIUS_PIXEL; + + Object *ob_eval = gso->ob_eval; + bGPdata *gpd = (bGPdata *)ob_eval->data; + GP_SpaceConversion *gsc = &gso->gsc; + const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); + float dist = FLT_MAX; + + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + if (!BKE_gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) { + continue; + } + /* Calculate bound box matrix. */ + float bound_mat[4][4]; + BKE_gpencil_layer_transform_matrix_get(gso->depsgraph, gso->object, gpl, bound_mat); + + bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe; + for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps; + if (gps->totpoints == 0) { + continue; + } + /* Check if the color is editable. */ + if (ED_gpencil_stroke_material_editable(gso->object, gpl, gps) == false) { + continue; + } + + /* Check if the stroke collide with brush. */ + if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, bound_mat)) { + continue; + } + + bGPDspoint *pt; + int pc2D[2] = {0}; + bGPDspoint npt; + + for (int i = 0; i < gps->totpoints; i++) { + pt = gps->points + i; + gpencil_point_to_world_space(pt, bound_mat, &npt); + gpencil_point_to_xy(gsc, gps, &npt, &pc2D[0], &pc2D[1]); + float d = len_v2v2_int(mval_i, pc2D); + if (d < dist) { + dist = d; + *r_gpl = gpl; + *r_gps = gps_active; + } + } + } + /* If not multi-edit, exit loop. */ + if (!is_multiedit) { + break; + } + } + } +} + /* Get list of Auto-Masking strokes. */ static bool get_automasking_strokes_list(tGP_BrushEditData *gso) { - bGPdata *gpd = gso->gpd; + Object *ob_eval = gso->ob_eval; + bGPdata *gpd = (bGPdata *)ob_eval->data; GP_SpaceConversion *gsc = &gso->gsc; - Brush *brush = gso->brush; + ToolSettings *ts = gso->scene->toolsettings; Object *ob = gso->object; - Material *mat_active = BKE_gpencil_material(ob, ob->actcol); + const eGP_Sculpt_SettingsFlag flag = ts->gp_sculpt.flag; const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); - const bool is_masking_stroke = (brush->gpencil_settings->sculpt_mode_flag & - GP_SCULPT_FLAGMODE_AUTOMASK_STROKE) != 0; - const bool is_masking_layer = (brush->gpencil_settings->sculpt_mode_flag & - GP_SCULPT_FLAGMODE_AUTOMASK_LAYER) != 0; - const bool is_masking_material = (brush->gpencil_settings->sculpt_mode_flag & - GP_SCULPT_FLAGMODE_AUTOMASK_MATERIAL) != 0; + const bool is_masking_stroke = (flag & GP_SCULPT_SETT_FLAG_AUTOMASK_STROKE) != 0; + const bool is_masking_layer_stroke = (flag & GP_SCULPT_SETT_FLAG_AUTOMASK_LAYER_STROKE) != 0; + const bool is_masking_material_stroke = (flag & GP_SCULPT_SETT_FLAG_AUTOMASK_MATERIAL_STROKE) != + 0; + const bool is_masking_layer_active = (flag & GP_SCULPT_SETT_FLAG_AUTOMASK_LAYER_ACTIVE) != 0; + const bool is_masking_material_active = (flag & GP_SCULPT_SETT_FLAG_AUTOMASK_MATERIAL_ACTIVE) != + 0; int mval_i[2]; round_v2i_v2fl(mval_i, gso->mval); /* Define a fix number of pixel as cursor radius. */ - const int radius = 10; + const int radius = SEARCH_RADIUS_PIXEL; bGPDlayer *gpl_active = BKE_gpencil_layer_active_get(gpd); + Material *mat_active = BKE_gpencil_material(ob, ob->actcol); + + /* By default use active values. */ + bGPDlayer *gpl_active_stroke = gpl_active; + Material *mat_active_stroke = mat_active; + /* Find nearest stroke to find the layer and material. */ + if (is_masking_layer_stroke || is_masking_material_stroke) { + bGPDlayer *gpl_near = NULL; + bGPDstroke *gps_near = NULL; + get_nearest_stroke_to_brush(gso, mval_i, &gpl_near, &gps_near); + if (gps_near != NULL) { + if (is_masking_layer_stroke) { + gpl_active_stroke = gpl_near; + } + if (is_masking_material_stroke) { + mat_active_stroke = BKE_object_material_get(ob, gps_near->mat_nr + 1); + } + } + } LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { /* Only editable and visible layers are considered. */ @@ -1777,87 +1873,113 @@ static bool get_automasking_strokes_list(tGP_BrushEditData *gso) bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe; for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps; + bool pick_stroke = false; + bool pick_layer_stroke = false; + bool pick_material_stroke = false; + bool pick_layer_active = false; + bool pick_material_active = false; + if (gps->totpoints == 0) { continue; } - /* Check if the color is editable. */ + /* Check if the material is editable. */ if (ED_gpencil_stroke_material_editable(gso->object, gpl, gps) == false) { continue; } - /* Layer Auto-Masking. */ - if ((is_masking_layer) && (gpl == gpl_active)) { - BLI_ghash_insert(gso->automasking_strokes, gps, gps); - continue; + /* Stroke Layer Auto-Masking. */ + if (is_masking_layer_stroke && (gpl == gpl_active_stroke)) { + pick_layer_stroke = true; } - /* Material Auto-Masking. */ - if (is_masking_material) { + /* Active Layer Auto-Masking. */ + if (is_masking_layer_active && (gpl == gpl_active)) { + pick_layer_active = true; + } + /* Stroke Material Auto-Masking. */ + if (is_masking_material_stroke) { Material *mat = BKE_object_material_get(ob, gps->mat_nr + 1); - if (mat == mat_active) { - BLI_ghash_insert(gso->automasking_strokes, gps, gps); - continue; + if (mat == mat_active_stroke) { + pick_material_stroke = true; } } - - /* If Stroke Auto-Masking is not enabled, nothing else to do. */ - if (!is_masking_stroke) { - continue; + /* Active Material Auto-Masking. */ + if (is_masking_material_active) { + Material *mat = BKE_object_material_get(ob, gps->mat_nr + 1); + if (mat == mat_active) { + pick_material_active = true; + } } /* Check if the stroke collide with brush. */ - if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, bound_mat)) { - continue; - } - - bGPDspoint *pt1, *pt2; - int pc1[2] = {0}; - int pc2[2] = {0}; - bGPDspoint npt; + if ((is_masking_stroke) && + ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, bound_mat)) { - if (gps->totpoints == 1) { - gpencil_point_to_world_space(gps->points, bound_mat, &npt); - gpencil_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]); + bGPDspoint *pt1, *pt2; + int pc1[2] = {0}; + int pc2[2] = {0}; + bGPDspoint npt; - /* Only check if point is inside. */ - if (len_v2v2_int(mval_i, pc1) <= radius) { - BLI_ghash_insert(gso->automasking_strokes, gps, gps); - } - } - else { - /* Loop over the points in the stroke, checking for intersections - * - an intersection means that we touched the stroke. - */ - for (int i = 0; (i + 1) < gps->totpoints; i++) { - /* Get points to work with. */ - pt1 = gps->points + i; - pt2 = gps->points + i + 1; - - /* Check first point. */ - gpencil_point_to_world_space(pt1, bound_mat, &npt); + if (gps->totpoints == 1) { + gpencil_point_to_world_space(gps->points, bound_mat, &npt); gpencil_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]); - if (len_v2v2_int(mval_i, pc1) <= radius) { - BLI_ghash_insert(gso->automasking_strokes, gps, gps); - i = gps->totpoints; - continue; - } - /* Check second point. */ - gpencil_point_to_world_space(pt2, bound_mat, &npt); - gpencil_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]); - if (len_v2v2_int(mval_i, pc2) <= radius) { - BLI_ghash_insert(gso->automasking_strokes, gps, gps); - i = gps->totpoints; - continue; + /* Only check if point is inside. */ + if (len_v2v2_int(mval_i, pc1) <= radius) { + pick_stroke = true; } - - /* Check segment. */ - if (gpencil_stroke_inside_circle(gso->mval, radius, pc1[0], pc1[1], pc2[0], pc2[1])) { - BLI_ghash_insert(gso->automasking_strokes, gps, gps); - i = gps->totpoints; - continue; + } + else { + /* Loop over the points in the stroke, checking for intersections + * - an intersection means that we touched the stroke. + */ + for (int i = 0; (i + 1) < gps->totpoints && !pick_stroke; i++) { + /* Get points to work with. */ + pt1 = gps->points + i; + pt2 = gps->points + i + 1; + + /* Check first point. */ + gpencil_point_to_world_space(pt1, bound_mat, &npt); + gpencil_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]); + if (len_v2v2_int(mval_i, pc1) <= radius) { + pick_stroke = true; + i = gps->totpoints; + } + + /* Check second point. */ + gpencil_point_to_world_space(pt2, bound_mat, &npt); + gpencil_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]); + if (len_v2v2_int(mval_i, pc2) <= radius) { + pick_stroke = true; + i = gps->totpoints; + } + + /* Check segment. */ + if (!pick_stroke && gpencil_stroke_inside_circle( + gso->mval, radius, pc1[0], pc1[1], pc2[0], pc2[1])) { + pick_stroke = true; + i = gps->totpoints; + } } } } + /* if the stroke meets all the masking conditions, add to the hash table. */ + if (is_masking_stroke && !pick_stroke) { + continue; + } + if (is_masking_layer_stroke && !pick_layer_stroke) { + continue; + } + if (is_masking_material_stroke && !pick_material_stroke) { + continue; + } + if (is_masking_layer_active && !pick_layer_active) { + continue; + } + if (is_masking_material_active && !pick_material_active) { + continue; + } + BLI_ghash_insert(gso->automasking_strokes, gps_active, gps_active); } /* If not multi-edit, exit loop. */ if (!is_multiedit) { @@ -1877,7 +1999,7 @@ static bool gpencil_sculpt_brush_apply_standard(bContext *C, tGP_BrushEditData * Object *obact = gso->object; bool changed = false; - Object *ob_eval = (Object *)DEG_get_evaluated_id(depsgraph, &obact->id); + Object *ob_eval = gso->ob_eval; bGPdata *gpd = (bGPdata *)ob_eval->data; /* Calculate brush-specific data which applies equally to all points */ @@ -1971,6 +2093,7 @@ static void gpencil_sculpt_brush_apply(bContext *C, wmOperator *op, PointerRNA * { tGP_BrushEditData *gso = op->customdata; Brush *brush = gso->brush; + ToolSettings *ts = gso->scene->toolsettings; const int radius = (brush->flag & GP_BRUSH_USE_PRESSURE) ? gso->brush->size * gso->pressure : gso->brush->size; float mousef[2]; @@ -2012,9 +2135,10 @@ static void gpencil_sculpt_brush_apply(bContext *C, wmOperator *op, PointerRNA * /* Get list of Auto-Masking strokes. */ if ((!gso->automasking_ready) && - (brush->gpencil_settings->sculpt_mode_flag & - (GP_SCULPT_FLAGMODE_AUTOMASK_STROKE | GP_SCULPT_FLAGMODE_AUTOMASK_LAYER | - GP_SCULPT_FLAGMODE_AUTOMASK_MATERIAL))) { + (ts->gp_sculpt.flag & + (GP_SCULPT_SETT_FLAG_AUTOMASK_STROKE | GP_SCULPT_SETT_FLAG_AUTOMASK_LAYER_STROKE | + GP_SCULPT_SETT_FLAG_AUTOMASK_MATERIAL_STROKE | GP_SCULPT_SETT_FLAG_AUTOMASK_LAYER_ACTIVE | + GP_SCULPT_SETT_FLAG_AUTOMASK_MATERIAL_ACTIVE))) { gso->automasking_ready = get_automasking_strokes_list(gso); } @@ -2082,20 +2206,6 @@ static void gpencil_sculpt_brush_apply_event(bContext *C, wmOperator *op, const if (gso->brush == NULL) { gso->brush = gso->brush_prev; } - Brush *brush = gso->brush; - if (brush->gpencil_settings->sculpt_mode_flag & - (GP_SCULPT_FLAGMODE_AUTOMASK_STROKE | GP_SCULPT_FLAGMODE_AUTOMASK_LAYER | - GP_SCULPT_FLAGMODE_AUTOMASK_MATERIAL)) { - if (gso->automasking_strokes == NULL) { - gso->automasking_strokes = BLI_ghash_ptr_new(__func__); - } - } - else { - if (gso->automasking_strokes != NULL) { - BLI_ghash_free(gso->automasking_strokes, NULL, NULL); - } - gso->automasking_strokes = NULL; - } } else { if (gso->brush_prev != NULL) { diff --git a/source/blender/editors/gpencil/gpencil_trace_ops.c b/source/blender/editors/gpencil/gpencil_trace_ops.c index 36165c6b7c0..1a18e10412e 100644 --- a/source/blender/editors/gpencil/gpencil_trace_ops.c +++ b/source/blender/editors/gpencil/gpencil_trace_ops.c @@ -45,7 +45,7 @@ typedef struct TraceJob { /* from wmJob */ struct Object *owner; - short *stop, *do_update; + bool *stop, *do_update; float *progress; bContext *C; @@ -198,7 +198,7 @@ static void trace_initialize_job_data(TraceJob *trace_job) } } -static void trace_start_job(void *customdata, short *stop, short *do_update, float *progress) +static void trace_start_job(void *customdata, bool *stop, bool *do_update, float *progress) { TraceJob *trace_job = customdata; @@ -257,7 +257,7 @@ static void trace_start_job(void *customdata, short *stop, short *do_update, flo trace_job->success = !trace_job->was_canceled; *do_update = true; - *stop = 0; + *stop = false; } static void trace_end_job(void *customdata) @@ -339,7 +339,7 @@ static int gpencil_trace_image_exec(bContext *C, wmOperator *op) ED_object_base_activate(job->C, job->base_active); if ((job->image->source == IMA_SRC_FILE) || (job->frame_num > 0)) { - short stop = 0, do_update = true; + bool stop = false, do_update = true; float progress; trace_start_job(job, &stop, &do_update, &progress); trace_end_job(job); diff --git a/source/blender/editors/include/ED_geometry.h b/source/blender/editors/include/ED_geometry.h index 4620181894a..8436df73d10 100644 --- a/source/blender/editors/include/ED_geometry.h +++ b/source/blender/editors/include/ED_geometry.h @@ -15,14 +15,21 @@ extern "C" { #endif struct Mesh; +struct ReportList; void ED_operatortypes_geometry(void); + +/** + * Convert an attribute with the given name to a new type and domain. + * The attribute must already exist. + * + * \note Does not support meshes in edit mode. + */ bool ED_geometry_attribute_convert(struct Mesh *mesh, - const char *layer_name, - eCustomDataType old_type, - eAttrDomain old_domain, - eCustomDataType new_type, - eAttrDomain new_domain); + const char *name, + eCustomDataType dst_type, + eAttrDomain dst_domain, + ReportList *reports); #ifdef __cplusplus } #endif diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h index da303f3552b..20e62ac8626 100644 --- a/source/blender/editors/include/ED_image.h +++ b/source/blender/editors/include/ED_image.h @@ -51,6 +51,7 @@ void ED_space_image_set(struct Main *bmain, struct SpaceImage *sima, struct Image *ima, bool automatic); +void ED_space_image_sync(struct Main *bmain, Image *image, bool ignore_render_viewer); void ED_space_image_auto_set(const struct bContext *C, struct SpaceImage *sima); struct Mask *ED_space_image_get_mask(const struct SpaceImage *sima); void ED_space_image_set_mask(struct bContext *C, struct SpaceImage *sima, struct Mask *mask); diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index c100bf9b60b..52527f6c1b8 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -142,12 +142,15 @@ struct UvElementMap *BM_uv_element_map_create(struct BMesh *bm, bool use_seams, bool do_islands); void BM_uv_element_map_free(struct UvElementMap *element_map); -struct UvElement *BM_uv_element_get(const struct UvElementMap *map, +struct UvElement *BM_uv_element_get(const struct UvElementMap *element_map, const struct BMFace *efa, const struct BMLoop *l); -struct UvElement *BM_uv_element_get_head(struct UvElementMap *map, struct UvElement *child); +struct UvElement *BM_uv_element_get_head(struct UvElementMap *element_map, + struct UvElement *child); +int BM_uv_element_get_unique_index(struct UvElementMap *element_map, struct UvElement *child); struct UvElement **BM_uv_element_map_ensure_head_table(struct UvElementMap *element_map); +int *BM_uv_element_map_ensure_unique_index(struct UvElementMap *element_map); /** * Can we edit UV's for this mesh? diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h index 1c1ce41ef7a..bc4e3b88586 100644 --- a/source/blender/editors/include/ED_sculpt.h +++ b/source/blender/editors/include/ED_sculpt.h @@ -22,7 +22,7 @@ struct wmMsgSubscribeValue; struct wmRegionMessageSubscribeParams; struct wmOperator; -/* sculpt.c */ +/* sculpt.cc */ void ED_operatortypes_sculpt(void); void ED_sculpt_redraw_planes_get(float planes[4][4], struct ARegion *region, struct Object *ob); diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h index b97cd6a9099..5fea8711a84 100644 --- a/source/blender/editors/include/ED_uvedit.h +++ b/source/blender/editors/include/ED_uvedit.h @@ -73,8 +73,8 @@ bool ED_object_get_active_image(struct Object *ob, int mat_nr, struct Image **r_ima, struct ImageUser **r_iuser, - struct bNode **r_node, - struct bNodeTree **r_ntree); + const struct bNode **r_node, + const struct bNodeTree **r_ntree); void ED_object_assign_active_image(struct Main *bmain, struct Object *ob, int mat_nr, diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 66b3d9fba6b..415356d1d71 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -1789,7 +1789,6 @@ void UI_but_drag_attach_image(uiBut *but, struct ImBuf *imb, float scale); void UI_but_drag_set_asset(uiBut *but, const struct AssetHandle *asset, const char *path, - struct AssetMetaData *metadata, int import_type, /* eFileAssetImportType */ int icon, struct ImBuf *imb, diff --git a/source/blender/editors/interface/interface_drag.cc b/source/blender/editors/interface/interface_drag.cc index 4bf2dac4151..e959986d19e 100644 --- a/source/blender/editors/interface/interface_drag.cc +++ b/source/blender/editors/interface/interface_drag.cc @@ -27,15 +27,14 @@ void UI_but_drag_attach_image(uiBut *but, struct ImBuf *imb, const float scale) } void UI_but_drag_set_asset(uiBut *but, - const AssetHandle *asset, + const AssetHandle *asset_handle, const char *path, - struct AssetMetaData *metadata, int import_type, int icon, struct ImBuf *imb, float scale) { - wmDragAsset *asset_drag = WM_drag_create_asset_data(asset, metadata, path, import_type); + wmDragAsset *asset_drag = WM_drag_create_asset_data(asset_handle, path, import_type); /* FIXME: This is temporary evil solution to get scene/view-layer/etc in the copy callback of the * #wmDropBox. diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index 9a4f98ebcd6..a5e2cd02f3b 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -1309,8 +1309,8 @@ static void ui_id_preview_image_render_size( const bContext *C, Scene *scene, ID *id, PreviewImage *pi, int size, const bool use_job); static void ui_studiolight_icon_job_exec(void *customdata, - short *UNUSED(stop), - short *UNUSED(do_update), + bool *UNUSED(stop), + bool *UNUSED(do_update), float *UNUSED(progress)) { Icon **tmp = (Icon **)customdata; diff --git a/source/blender/editors/interface/interface_panel.cc b/source/blender/editors/interface/interface_panel.cc index 24d8281aad8..05b6ecf29d5 100644 --- a/source/blender/editors/interface/interface_panel.cc +++ b/source/blender/editors/interface/interface_panel.cc @@ -2026,7 +2026,7 @@ static void ui_panel_drag_collapse_handler_add(const bContext *C, const bool was ui_panel_drag_collapse_handler, ui_panel_drag_collapse_handler_remove, dragcol_data, - 0); + eWM_EventHandlerFlag(0)); } /** @@ -2510,8 +2510,12 @@ static void panel_handle_data_ensure(const bContext *C, { if (panel->activedata == nullptr) { panel->activedata = MEM_callocN(sizeof(uiHandlePanelData), __func__); - WM_event_add_ui_handler( - C, &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, panel, 0); + WM_event_add_ui_handler(C, + &win->modalhandlers, + ui_handler_panel, + ui_handler_remove_panel, + panel, + eWM_EventHandlerFlag(0)); } uiHandlePanelData *data = static_cast<uiHandlePanelData *>(panel->activedata); diff --git a/source/blender/editors/interface/interface_region_menu_popup.cc b/source/blender/editors/interface/interface_region_menu_popup.cc index 871fd5c6166..8fd6731d2ec 100644 --- a/source/blender/editors/interface/interface_region_menu_popup.cc +++ b/source/blender/editors/interface/interface_region_menu_popup.cc @@ -286,13 +286,13 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi int width, height; UI_block_layout_resolve(block, &width, &height); - UI_block_flag_enable(block, UI_BLOCK_MOVEMOUSE_QUIT); + UI_block_flag_enable(block, UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_NUMSELECT); if (pup->popup) { int offset[2] = {0, 0}; uiBut *but_activate = nullptr; - UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_NUMSELECT); + UI_block_flag_enable(block, UI_BLOCK_LOOP); UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP); UI_block_direction_set(block, direction); diff --git a/source/blender/editors/interface/interface_template_asset_view.cc b/source/blender/editors/interface/interface_template_asset_view.cc index 11fe653724c..9a3f7800c64 100644 --- a/source/blender/editors/interface/interface_template_asset_view.cc +++ b/source/blender/editors/interface/interface_template_asset_view.cc @@ -57,7 +57,6 @@ static void asset_view_item_but_drag_set(uiBut *but, UI_but_drag_set_asset(but, asset_handle, BLI_strdup(blend_path), - ED_asset_handle_get_metadata(asset_handle), FILE_ASSET_IMPORT_APPEND, ED_asset_handle_get_preview_icon_id(asset_handle), imbuf, diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index a3259831c9f..b32aa82ad9e 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -3673,13 +3673,9 @@ static void colorband_buttons_layout(uiLayout *layout, row = uiLayoutRow(split, false); uiItemR(row, &ptr, "position", 0, IFACE_("Pos"), ICON_NONE); - bt = block->buttons.last; - UI_but_func_set(bt, colorband_update_cb, bt, coba); row = uiLayoutRow(layout, false); uiItemR(row, &ptr, "color", 0, "", ICON_NONE); - bt = block->buttons.last; - UI_but_funcN_set(bt, rna_update_cb, MEM_dupallocN(cb), NULL); } else { split = uiLayoutSplit(layout, 0.5f, false); @@ -3704,13 +3700,28 @@ static void colorband_buttons_layout(uiLayout *layout, row = uiLayoutRow(subsplit, false); uiItemR(row, &ptr, "position", UI_ITEM_R_SLIDER, IFACE_("Pos"), ICON_NONE); - bt = block->buttons.last; - UI_but_func_set(bt, colorband_update_cb, bt, coba); row = uiLayoutRow(split, false); uiItemR(row, &ptr, "color", 0, "", ICON_NONE); - bt = block->buttons.last; - UI_but_funcN_set(bt, rna_update_cb, MEM_dupallocN(cb), NULL); + } + + /* Some special (rather awkward) treatment to update UI state on certain property changes. */ + LISTBASE_FOREACH_BACKWARD (uiBut *, but, &block->buttons) { + if (but->rnapoin.data != ptr.data) { + continue; + } + if (!but->rnaprop) { + continue; + } + + const char *prop_identifier = RNA_property_identifier(but->rnaprop); + if (STREQ(prop_identifier, "position")) { + UI_but_func_set(but, colorband_update_cb, but, coba); + } + + if (STREQ(prop_identifier, "color")) { + UI_but_funcN_set(but, rna_update_cb, MEM_dupallocN(cb), NULL); + } } } } diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c index a630f150e0e..7bc28a0ba89 100644 --- a/source/blender/editors/io/io_collada.c +++ b/source/blender/editors/io/io_collada.c @@ -219,7 +219,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op) } char buff[100]; - sprintf(buff, "Exported %d Objects", export_count); + BLI_snprintf(buff, sizeof(buff), "Exported %d Objects", export_count); BKE_report(op->reports, RPT_INFO, buff); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index f6ffbec094e..bbc092d0a99 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -619,6 +619,44 @@ struct UvElement **BM_uv_element_map_ensure_head_table(struct UvElementMap *elem return element_map->head_table; } +int *BM_uv_element_map_ensure_unique_index(struct UvElementMap *element_map) +{ + if (!element_map->unique_index_table) { + element_map->unique_index_table = MEM_callocN( + element_map->total_uvs * sizeof(*element_map->unique_index_table), __func__); + + int j = 0; + for (int i = 0; i < element_map->total_uvs; i++) { + UvElement *element = element_map->storage + i; + if (!element->separate) { + continue; + } + BLI_assert(0 <= j); + BLI_assert(j < element_map->total_unique_uvs); + while (element) { + element_map->unique_index_table[element - element_map->storage] = j; + element = element->next; + if (!element || element->separate) { + break; + } + } + j++; + } + BLI_assert(j == element_map->total_unique_uvs); + } + + return element_map->unique_index_table; +} + +int BM_uv_element_get_unique_index(struct UvElementMap *element_map, struct UvElement *child) +{ + int *unique_index = BM_uv_element_map_ensure_unique_index(element_map); + int index = child - element_map->storage; + BLI_assert(0 <= index); + BLI_assert(index < element_map->total_uvs); + return unique_index[index]; +} + #define INVALID_ISLAND ((uint)-1) static void bm_uv_assign_island(UvElementMap *element_map, @@ -1163,6 +1201,7 @@ void BM_uv_element_map_free(UvElementMap *element_map) MEM_SAFE_FREE(element_map->storage); MEM_SAFE_FREE(element_map->vertex); MEM_SAFE_FREE(element_map->head_table); + MEM_SAFE_FREE(element_map->unique_index_table); MEM_SAFE_FREE(element_map->island_indices); MEM_SAFE_FREE(element_map->island_total_uvs); MEM_SAFE_FREE(element_map->island_total_unique_uvs); diff --git a/source/blender/editors/mesh/mesh_data.cc b/source/blender/editors/mesh/mesh_data.cc index 6597a905a79..01cb1951c93 100644 --- a/source/blender/editors/mesh/mesh_data.cc +++ b/source/blender/editors/mesh/mesh_data.cc @@ -1193,7 +1193,7 @@ static void mesh_add_edges(Mesh *mesh, int len) MutableSpan<MEdge> edges = mesh->edges_for_write(); for (MEdge &edge : edges.take_back(len)) { - edge.flag = ME_EDGEDRAW | ME_EDGERENDER; + edge.flag = ME_EDGEDRAW; } bke::MutableAttributeAccessor attributes = mesh->attributes_for_write(); diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c index 4b6ce69294f..91641de1605 100644 --- a/source/blender/editors/object/object_bake.c +++ b/source/blender/editors/object/object_bake.c @@ -461,7 +461,7 @@ static void init_multiresbake_job(bContext *C, MultiresBakeJob *bkj) CTX_DATA_END; } -static void multiresbake_startjob(void *bkv, short *stop, short *do_update, float *progress) +static void multiresbake_startjob(void *bkv, bool *stop, bool *do_update, float *progress) { MultiresBakerJobData *data; MultiresBakeJob *bkj = bkv; diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index 1cd7c855b0f..6a415427558 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -106,7 +106,7 @@ typedef struct BakeAPIRender { /* Progress Callbacks. */ float *progress; - short *do_update; + bool *do_update; /* Operator state. */ ReportList *reports; @@ -150,12 +150,12 @@ static int bake_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) * for exec() when there is no render job * NOTE: this won't check for the escape key being pressed, but doing so isn't thread-safe. */ -static int bake_break(void *UNUSED(rjv)) +static bool bake_break(void *UNUSED(rjv)) { if (G.is_break) { - return 1; + return true; } - return 0; + return false; } static void bake_update_image(ScrArea *area, Image *image) @@ -467,8 +467,8 @@ static bool bake_object_check(const Scene *scene, } for (int i = 0; i < ob->totcol; i++) { - bNodeTree *ntree = NULL; - bNode *node = NULL; + const bNodeTree *ntree = NULL; + const bNode *node = NULL; const int mat_nr = i + 1; Image *image; ED_object_get_active_image(ob, mat_nr, &image, NULL, &node, &ntree); @@ -893,7 +893,7 @@ static bool bake_targets_output_external(const BakeAPIRender *bkr, else { /* if everything else fails, use the material index */ char tmp[5]; - sprintf(tmp, "%d", i % 1000); + BLI_snprintf(tmp, sizeof(tmp), "%d", i % 1000); BLI_path_suffix(name, FILE_MAX, tmp, "_"); } } @@ -1854,7 +1854,7 @@ finally: return result; } -static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, float *progress) +static void bake_startjob(void *bkv, bool *UNUSED(stop), bool *do_update, float *progress) { BakeAPIRender *bkr = (BakeAPIRender *)bkv; diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index 1386da5dbde..cbed01442ee 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -182,7 +182,7 @@ static char *buildmenu_pyconstraints(Main *bmain, Text *con_text, int *pyconinde int i; /* add title first */ - sprintf(buf, "Scripts: %%t|[None]%%x0|"); + BLI_snprintf(buf, sizeof(buf), "Scripts: %%t|[None]%%x0|"); BLI_dynstr_append(pupds, buf); /* init active-index first */ @@ -201,7 +201,7 @@ static char *buildmenu_pyconstraints(Main *bmain, Text *con_text, int *pyconinde if (BPY_is_pyconstraint(text)) { BLI_dynstr_append(pupds, text->id.name + 2); - sprintf(buf, "%%x%d", i); + BLI_snprintf(buf, sizeof(buf), "%%x%d", i); BLI_dynstr_append(pupds, buf); if (text->id.next) { diff --git a/source/blender/editors/object/object_modifier.cc b/source/blender/editors/object/object_modifier.cc index cb3b854909c..013bbbf7e55 100644 --- a/source/blender/editors/object/object_modifier.cc +++ b/source/blender/editors/object/object_modifier.cc @@ -615,7 +615,7 @@ bool ED_object_modifier_convert_psys_to_mesh(ReportList * /*reports*/, if (k) { medge->v1 = cvert - 1; medge->v2 = cvert; - medge->flag = ME_EDGEDRAW | ME_EDGERENDER | ME_LOOSEEDGE; + medge->flag = ME_EDGEDRAW | ME_LOOSEEDGE; medge++; } else { @@ -634,7 +634,7 @@ bool ED_object_modifier_convert_psys_to_mesh(ReportList * /*reports*/, if (k) { medge->v1 = cvert - 1; medge->v2 = cvert; - medge->flag = ME_EDGEDRAW | ME_EDGERENDER | ME_LOOSEEDGE; + medge->flag = ME_EDGEDRAW | ME_LOOSEEDGE; medge++; } else { @@ -943,31 +943,56 @@ bool ED_object_modifier_apply(Main *bmain, Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); ModifierData *md_eval = (ob_eval) ? BKE_modifiers_findby_name(ob_eval, md->name) : md; - /* Allow apply of a non-real-time modifier, by first re-enabling real-time. */ - int prev_mode = md_eval->mode; - md_eval->mode |= eModifierMode_Realtime; + Depsgraph *apply_depsgraph = depsgraph; + Depsgraph *local_depsgraph = nullptr; + + /* If the object is hidden or the modifier is not enabled for the viewport is disabled a special + * handling is required. This is because the viewport dependency graph optimizes out evaluation + * of objects which are used by hidden objects and disabled modifiers. + * + * The idea is to create a dependency graph which does not perform those optimizations. */ + if ((ob_eval->base_flag & BASE_ENABLED_VIEWPORT) == 0 || + (md_eval->mode & eModifierMode_Realtime) == 0) { + ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph); + + local_depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_VIEWPORT); + DEG_disable_visibility_optimization(local_depsgraph); + + ID *ids[] = {&ob->id}; + + DEG_graph_build_from_ids(local_depsgraph, ids, 1); + DEG_evaluate_on_refresh(local_depsgraph); + + apply_depsgraph = local_depsgraph; + + /* The evaluated object and modifier are now from the different dependency graph. */ + ob_eval = DEG_get_evaluated_object(local_depsgraph, ob); + md_eval = BKE_modifiers_findby_name(ob_eval, md->name); + + /* Force mode on the evaluated modifier, enforcing the modifier evaluation in the apply() + * functions. */ + md_eval->mode |= eModifierMode_Realtime; + } + bool did_apply = false; if (mode == MODIFIER_APPLY_SHAPE) { - if (!modifier_apply_shape(bmain, reports, depsgraph, scene, ob, md_eval)) { - md_eval->mode = prev_mode; - return false; - } + did_apply = modifier_apply_shape(bmain, reports, apply_depsgraph, scene, ob, md_eval); } else { - if (!modifier_apply_obdata(reports, depsgraph, scene, ob, md_eval)) { - md_eval->mode = prev_mode; - return false; - } + did_apply = modifier_apply_obdata(reports, apply_depsgraph, scene, ob, md_eval); } - md_eval->mode = prev_mode; - - if (!keep_modifier) { - BKE_modifier_remove_from_list(ob, md); - BKE_modifier_free(md); + if (did_apply) { + if (!keep_modifier) { + BKE_modifier_remove_from_list(ob, md); + BKE_modifier_free(md); + } + BKE_object_free_derived_caches(ob); } - BKE_object_free_derived_caches(ob); + if (local_depsgraph != nullptr) { + DEG_graph_free(local_depsgraph); + } return true; } @@ -3024,7 +3049,7 @@ static bool ocean_bake_poll(bContext *C) struct OceanBakeJob { /* from wmJob */ struct Object *owner; - short *stop, *do_update; + bool *stop, *do_update; float *progress; int current_frame; struct OceanCache *och; @@ -3063,7 +3088,7 @@ static void oceanbake_update(void *customdata, float progress, int *cancel) *(oj->progress) = progress; } -static void oceanbake_startjob(void *customdata, short *stop, short *do_update, float *progress) +static void oceanbake_startjob(void *customdata, bool *stop, bool *do_update, float *progress) { OceanBakeJob *oj = static_cast<OceanBakeJob *>(customdata); @@ -3076,7 +3101,7 @@ static void oceanbake_startjob(void *customdata, short *stop, short *do_update, BKE_ocean_bake(oj->ocean, oj->och, oceanbake_update, (void *)oj); *do_update = true; - *stop = 0; + *stop = false; } static void oceanbake_endjob(void *customdata) diff --git a/source/blender/editors/object/object_remesh.cc b/source/blender/editors/object/object_remesh.cc index 501adaf7506..8c133dfecfa 100644 --- a/source/blender/editors/object/object_remesh.cc +++ b/source/blender/editors/object/object_remesh.cc @@ -287,7 +287,7 @@ static void voxel_size_parallel_lines_draw(uint pos3d, immEnd(); } -static void voxel_size_edit_draw(const bContext *C, ARegion * /*ar*/, void *arg) +static void voxel_size_edit_draw(const bContext *C, ARegion * /*region*/, void *arg) { VoxelSizeEditCustomData *cd = static_cast<VoxelSizeEditCustomData *>(arg); @@ -655,7 +655,7 @@ enum eSymmetryAxes { struct QuadriFlowJob { /* from wmJob */ struct Object *owner; - short *stop, *do_update; + bool *stop, *do_update; float *progress; const struct wmOperator *op; @@ -835,7 +835,7 @@ static Mesh *remesh_symmetry_mirror(Object *ob, Mesh *mesh, eSymmetryAxes symmet return mesh_mirror; } -static void quadriflow_start_job(void *customdata, short *stop, short *do_update, float *progress) +static void quadriflow_start_job(void *customdata, bool *stop, bool *do_update, float *progress) { QuadriFlowJob *qj = static_cast<QuadriFlowJob *>(customdata); @@ -883,7 +883,7 @@ static void quadriflow_start_job(void *customdata, short *stop, short *do_update if (new_mesh == nullptr) { *do_update = true; - *stop = 0; + *stop = false; if (qj->success == 1) { /* This is not a user cancellation event. */ qj->success = 0; @@ -916,7 +916,7 @@ static void quadriflow_start_job(void *customdata, short *stop, short *do_update BKE_mesh_batch_cache_dirty_tag(static_cast<Mesh *>(ob->data), BKE_MESH_BATCH_DIRTY_ALL); *do_update = true; - *stop = 0; + *stop = false; } static void quadriflow_end_job(void *customdata) @@ -991,7 +991,7 @@ static int quadriflow_remesh_exec(bContext *C, wmOperator *op) if (op->flag == 0) { /* This is called directly from the exec operator, this operation is now blocking */ job->is_nonblocking_job = false; - short stop = 0, do_update = true; + bool stop = false, do_update = true; float progress; quadriflow_start_job(job, &stop, &do_update, &progress); quadriflow_end_job(job); diff --git a/source/blender/editors/object/object_transform.cc b/source/blender/editors/object/object_transform.cc index 0c2aca8b97b..7d0b62db827 100644 --- a/source/blender/editors/object/object_transform.cc +++ b/source/blender/editors/object/object_transform.cc @@ -7,6 +7,7 @@ #include <cstdlib> #include <cstring> +#include <limits> #include <numeric> #include "DNA_anim_types.h" @@ -1643,8 +1644,8 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) /* done */ } else if (around == V3D_AROUND_CENTER_BOUNDS) { - float3 min; - float3 max; + float3 min(std::numeric_limits<float>::max()); + float3 max(-std::numeric_limits<float>::max()); if (curves.bounds_min_max(min, max)) { cent = math::midpoint(min, max); } diff --git a/source/blender/editors/object/object_vgroup.cc b/source/blender/editors/object/object_vgroup.cc index 0814b7188e3..72b9b1b839c 100644 --- a/source/blender/editors/object/object_vgroup.cc +++ b/source/blender/editors/object/object_vgroup.cc @@ -1921,10 +1921,6 @@ static void vgroup_smooth_subset(Object *ob, BMesh *bm = em ? em->bm : nullptr; Mesh *me = em ? nullptr : static_cast<Mesh *>(ob->data); - const bke::AttributeAccessor attributes = me->attributes(); - const VArray<bool> select_vert = attributes.lookup_or_default<bool>( - ".select_vert", ATTR_DOMAIN_POINT, false); - MeshElemMap *emap; int *emap_mem; @@ -1988,6 +1984,10 @@ static void vgroup_smooth_subset(Object *ob, } } else { + const bke::AttributeAccessor attributes = me->attributes(); + const VArray<bool> select_vert = attributes.lookup_or_default<bool>( + ".select_vert", ATTR_DOMAIN_POINT, false); + const blender::Span<MEdge> edges = me->edges(); for (int i = 0; i < dvert_tot; i++) { if (IS_ME_VERT_WRITE(i)) { @@ -2060,6 +2060,10 @@ static void vgroup_smooth_subset(Object *ob, } } else { + const bke::AttributeAccessor attributes = me->attributes(); + const VArray<bool> select_vert = attributes.lookup_or_default<bool>( + ".select_vert", ATTR_DOMAIN_POINT, false); + int j; const blender::Span<MEdge> edges = me->edges(); diff --git a/source/blender/editors/physics/dynamicpaint_ops.c b/source/blender/editors/physics/dynamicpaint_ops.c index 41238eb171b..1a3f0f0f2ac 100644 --- a/source/blender/editors/physics/dynamicpaint_ops.c +++ b/source/blender/editors/physics/dynamicpaint_ops.c @@ -285,7 +285,7 @@ void DPAINT_OT_output_toggle(wmOperatorType *ot) typedef struct DynamicPaintBakeJob { /* from wmJob */ void *owner; - short *stop, *do_update; + bool *stop, *do_update; float *progress; struct Main *bmain; @@ -429,7 +429,7 @@ static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job) ED_update_for_newframe(job->bmain, job->depsgraph); } -static void dpaint_bake_startjob(void *customdata, short *stop, short *do_update, float *progress) +static void dpaint_bake_startjob(void *customdata, bool *stop, bool *do_update, float *progress) { DynamicPaintBakeJob *job = customdata; @@ -450,7 +450,7 @@ static void dpaint_bake_startjob(void *customdata, short *stop, short *do_update dynamicPaint_bakeImageSequence(job); *do_update = true; - *stop = 0; + *stop = false; } /* diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c index 314796e96e4..d5e55c99444 100644 --- a/source/blender/editors/physics/physics_fluid.c +++ b/source/blender/editors/physics/physics_fluid.c @@ -61,7 +61,7 @@ typedef struct FluidJob { /* from wmJob */ void *owner; - short *stop, *do_update; + bool *stop, *do_update; float *progress; const char *type; const char *name; @@ -349,7 +349,7 @@ static void fluid_bake_endjob(void *customdata) } } -static void fluid_bake_startjob(void *customdata, short *stop, short *do_update, float *progress) +static void fluid_bake_startjob(void *customdata, bool *stop, bool *do_update, float *progress) { FluidJob *job = customdata; FluidDomainSettings *fds = job->fmd->domain; @@ -428,7 +428,7 @@ static void fluid_bake_startjob(void *customdata, short *stop, short *do_update, *do_update = true; } if (stop) { - *stop = 0; + *stop = false; } } @@ -461,7 +461,7 @@ static void fluid_free_endjob(void *customdata) } } -static void fluid_free_startjob(void *customdata, short *stop, short *do_update, float *progress) +static void fluid_free_startjob(void *customdata, bool *stop, bool *do_update, float *progress) { FluidJob *job = customdata; FluidDomainSettings *fds = job->fmd->domain; @@ -504,7 +504,7 @@ static void fluid_free_startjob(void *customdata, short *stop, short *do_update, #endif *do_update = true; - *stop = 0; + *stop = false; /* Update scene so that viewport shows freed up scene */ ED_update_for_newframe(job->bmain, job->depsgraph); diff --git a/source/blender/editors/physics/physics_pointcache.c b/source/blender/editors/physics/physics_pointcache.c index 97cd0d1d149..9fac93187ee 100644 --- a/source/blender/editors/physics/physics_pointcache.c +++ b/source/blender/editors/physics/physics_pointcache.c @@ -86,7 +86,7 @@ static bool ptcache_add_remove_poll(bContext *C) typedef struct PointCacheJob { wmWindowManager *wm; void *owner; - short *stop, *do_update; + bool *stop, *do_update; float *progress; PTCacheBaker *baker; @@ -126,7 +126,7 @@ static void ptcache_job_update(void *customdata, float progress, int *cancel) *(job->progress) = progress; } -static void ptcache_job_startjob(void *customdata, short *stop, short *do_update, float *progress) +static void ptcache_job_startjob(void *customdata, bool *stop, bool *do_update, float *progress) { PointCacheJob *job = customdata; @@ -144,7 +144,7 @@ static void ptcache_job_startjob(void *customdata, short *stop, short *do_update BKE_ptcache_bake(job->baker); *do_update = true; - *stop = 0; + *stop = false; } static void ptcache_job_endjob(void *customdata) diff --git a/source/blender/editors/render/render_internal.cc b/source/blender/editors/render/render_internal.cc index e66cabbc9f8..5abf5867f92 100644 --- a/source/blender/editors/render/render_internal.cc +++ b/source/blender/editors/render/render_internal.cc @@ -69,7 +69,7 @@ #include "render_intern.hh" /* Render Callbacks */ -static int render_break(void *rjv); +static bool render_break(void *rjv); struct RenderJob { Main *main; @@ -87,8 +87,8 @@ struct RenderJob { Image *image; ImageUser iuser; bool image_outdated; - short *stop; - short *do_update; + bool *stop; + bool *do_update; float *progress; ReportList *reports; int orig_layer; @@ -405,56 +405,57 @@ static void make_renderinfo_string(const RenderStats *rs, /* local view */ if (rs->localview) { - spos += sprintf(spos, "%s | ", TIP_("3D Local View")); + spos += BLI_sprintf(spos, "%s | ", TIP_("3D Local View")); } else if (v3d_override) { - spos += sprintf(spos, "%s | ", TIP_("3D View")); + spos += BLI_sprintf(spos, "%s | ", TIP_("3D View")); } /* frame number */ - spos += sprintf(spos, TIP_("Frame:%d "), (scene->r.cfra)); + spos += BLI_sprintf(spos, TIP_("Frame:%d "), (scene->r.cfra)); /* previous and elapsed time */ BLI_timecode_string_from_time_simple(info_time_str, sizeof(info_time_str), rs->lastframetime); if (rs->infostr && rs->infostr[0]) { if (rs->lastframetime != 0.0) { - spos += sprintf(spos, TIP_("| Last:%s "), info_time_str); + spos += BLI_sprintf(spos, TIP_("| Last:%s "), info_time_str); } else { - spos += sprintf(spos, "| "); + spos += BLI_sprintf(spos, "| "); } BLI_timecode_string_from_time_simple( info_time_str, sizeof(info_time_str), PIL_check_seconds_timer() - rs->starttime); } else { - spos += sprintf(spos, "| "); + spos += BLI_sprintf(spos, "| "); } - spos += sprintf(spos, TIP_("Time:%s "), info_time_str); + spos += BLI_sprintf(spos, TIP_("Time:%s "), info_time_str); /* statistics */ if (rs->statstr) { if (rs->statstr[0]) { - spos += sprintf(spos, "| %s ", rs->statstr); + spos += BLI_sprintf(spos, "| %s ", rs->statstr); } } else { if (rs->mem_peak == 0.0f) { - spos += sprintf(spos, TIP_("| Mem:%.2fM (Peak %.2fM) "), megs_used_memory, megs_peak_memory); + spos += BLI_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); + spos += BLI_sprintf(spos, TIP_("| Mem:%.2fM, Peak: %.2fM "), rs->mem_used, rs->mem_peak); } } /* extra info */ if (rs->infostr && rs->infostr[0]) { - spos += sprintf(spos, "| %s ", rs->infostr); + spos += BLI_sprintf(spos, "| %s ", rs->infostr); } else if (error && error[0]) { - spos += sprintf(spos, "| %s ", error); + spos += BLI_sprintf(spos, "| %s ", error); } /* very weak... but 512 characters is quite safe */ @@ -637,7 +638,7 @@ static void current_scene_update(void *rjv, Scene *scene) rj->iuser.scene = scene; } -static void render_startjob(void *rjv, short *stop, short *do_update, float *progress) +static void render_startjob(void *rjv, bool *stop, bool *do_update, float *progress) { RenderJob *rj = static_cast<RenderJob *>(rjv); @@ -791,29 +792,29 @@ static void render_endjob(void *rjv) } /* called by render, check job 'stop' value or the global */ -static int render_breakjob(void *rjv) +static bool render_breakjob(void *rjv) { RenderJob *rj = static_cast<RenderJob *>(rjv); if (G.is_break) { - return 1; + return true; } if (rj->stop && *(rj->stop)) { - return 1; + return true; } - return 0; + return false; } /** * For exec() when there is no render job * NOTE: this won't check for the escape key being pressed, but doing so isn't thread-safe. */ -static int render_break(void * /*rjv*/) +static bool render_break(void * /*rjv*/) { if (G.is_break) { - return 1; + return true; } - return 0; + return false; } /* runs in thread, no cursor setting here works. careful with notifiers too (malloc conflicts) */ diff --git a/source/blender/editors/render/render_preview.cc b/source/blender/editors/render/render_preview.cc index 5aae48b1138..09394ea33be 100644 --- a/source/blender/editors/render/render_preview.cc +++ b/source/blender/editors/render/render_preview.cc @@ -104,7 +104,7 @@ static void icon_copy_rect(ImBuf *ibuf, uint w, uint h, uint *rect); struct ShaderPreview { /* from wmJob */ void *owner; - short *stop, *do_update; + bool *stop, *do_update; Scene *scene; ID *id, *id_copy; @@ -630,10 +630,10 @@ static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect bool ok = false; if (!split || first) { - sprintf(name, "Preview %p", (void *)area); + BLI_snprintf(name, sizeof(name), "Preview %p", (void *)area); } else { - sprintf(name, "SecondPreview %p", (void *)area); + BLI_snprintf(name, sizeof(name), "SecondPreview %p", (void *)area); } if (split) { @@ -1047,7 +1047,7 @@ static void shader_preview_update(void *spv, RenderResult * /*rr*/, struct rcti } /* called by renderer, checks job value */ -static int shader_preview_break(void *spv) +static bool shader_preview_break(void *spv) { ShaderPreview *sp = static_cast<ShaderPreview *>(spv); @@ -1152,10 +1152,10 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs } if (!split || first) { - sprintf(name, "Preview %p", sp->owner); + BLI_snprintf(name, sizeof(name), "Preview %p", sp->owner); } else { - sprintf(name, "SecondPreview %p", sp->owner); + BLI_snprintf(name, sizeof(name), "SecondPreview %p", sp->owner); } re = RE_GetRender(name); @@ -1223,7 +1223,7 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs } /* runs inside thread for material and icons */ -static void shader_preview_startjob(void *customdata, short *stop, short *do_update) +static void shader_preview_startjob(void *customdata, bool *stop, bool *do_update) { ShaderPreview *sp = static_cast<ShaderPreview *>(customdata); @@ -1408,7 +1408,7 @@ static void set_alpha(char *cp, int sizex, int sizey, char alpha) } } -static void icon_preview_startjob(void *customdata, short *stop, short *do_update) +static void icon_preview_startjob(void *customdata, bool *stop, bool *do_update) { ShaderPreview *sp = static_cast<ShaderPreview *>(customdata); @@ -1488,8 +1488,8 @@ static void icon_preview_startjob(void *customdata, short *stop, short *do_updat * does not run two of them at the same time. */ static void common_preview_startjob(void *customdata, - short *stop, - short *do_update, + bool *stop, + bool *do_update, float * /*progress*/) { ShaderPreview *sp = static_cast<ShaderPreview *>(customdata); @@ -1509,8 +1509,8 @@ static void common_preview_startjob(void *customdata, static void other_id_types_preview_render(IconPreview *ip, IconPreviewSize *cur_size, const ePreviewRenderMethod pr_method, - short *stop, - short *do_update, + bool *stop, + bool *do_update, float *progress) { ShaderPreview *sp = MEM_cnew<ShaderPreview>("Icon ShaderPreview"); @@ -1570,8 +1570,8 @@ static int icon_previewimg_size_index_get(const IconPreviewSize *icon_size, } static void icon_preview_startjob_all_sizes(void *customdata, - short *stop, - short *do_update, + bool *stop, + bool *do_update, float *progress) { IconPreview *ip = (IconPreview *)customdata; @@ -1735,7 +1735,7 @@ class PreviewLoadJob { void push_load_request(PreviewImage *preview, eIconSizes icon_size); private: - static void run_fn(void *customdata, short *stop, short *do_update, float *progress); + static void run_fn(void *customdata, bool *stop, bool *do_update, float *progress); static void update_fn(void *customdata); static void end_fn(void *customdata); static void free_fn(void *customdata); @@ -1755,7 +1755,8 @@ PreviewLoadJob::~PreviewLoadJob() PreviewLoadJob &PreviewLoadJob::ensure_job(wmWindowManager *wm, wmWindow *win) { - wmJob *wm_job = WM_jobs_get(wm, win, nullptr, "Load Previews", 0, WM_JOB_TYPE_LOAD_PREVIEW); + wmJob *wm_job = WM_jobs_get( + wm, win, nullptr, "Load Previews", eWM_JobFlag(0), WM_JOB_TYPE_LOAD_PREVIEW); if (!WM_jobs_is_running(wm_job)) { PreviewLoadJob *job_data = MEM_new<PreviewLoadJob>("PreviewLoadJobData"); @@ -1776,7 +1777,7 @@ void PreviewLoadJob::load_jobless(PreviewImage *preview, const eIconSizes icon_s job_data.push_load_request(preview, icon_size); - short stop = 0, do_update = 0; + bool stop = false, do_update = false; float progress = 0; run_fn(&job_data, &stop, &do_update, &progress); update_fn(&job_data); @@ -1798,7 +1799,7 @@ void PreviewLoadJob::push_load_request(PreviewImage *preview, const eIconSizes i BLI_thread_queue_push(todo_queue_, &requested_previews_.back()); } -void PreviewLoadJob::run_fn(void *customdata, short *stop, short *do_update, float * /*progress*/) +void PreviewLoadJob::run_fn(void *customdata, bool *stop, bool *do_update, float * /*progress*/) { PreviewLoadJob *job_data = static_cast<PreviewLoadJob *>(customdata); @@ -1936,7 +1937,7 @@ void ED_preview_icon_render( } IconPreview ip = {nullptr}; - short stop = false, update = false; + bool stop = false, update = false; float progress = 0.0f; ED_preview_ensure_dbase(); diff --git a/source/blender/editors/render/render_shading.cc b/source/blender/editors/render/render_shading.cc index 83ce447e8cf..e5c2b9702e5 100644 --- a/source/blender/editors/render/render_shading.cc +++ b/source/blender/editors/render/render_shading.cc @@ -1398,7 +1398,7 @@ static int light_cache_bake_exec(bContext *C, wmOperator *op) light_cache_bake_tag_cache(scene, op); - short stop = 0, do_update; + bool stop = false, do_update; float progress; /* Not actually used. */ EEVEE_lightbake_job(rj, &stop, &do_update, &progress); EEVEE_lightbake_job_data_free(rj); diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index 2709ac3fd91..b29fc0e9e7d 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -60,7 +60,7 @@ set(SRC paint_vertex_proj.c paint_vertex_weight_ops.c paint_vertex_weight_utils.c - sculpt.c + sculpt.cc sculpt_automasking.cc sculpt_boundary.c sculpt_brush_types.c diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index b85b878af7d..b6e83187c86 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -562,31 +562,36 @@ static bool paint_draw_tex_overlay(UnifiedPaintSettings *ups, if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) { GPU_matrix_push(); + float center[2] = { + ups->draw_anchored ? ups->anchored_initial_mouse[0] : x, + ups->draw_anchored ? ups->anchored_initial_mouse[1] : y, + }; + /* Brush rotation. */ - GPU_matrix_translate_2f(x, y); + GPU_matrix_translate_2fv(center); GPU_matrix_rotate_2d(-RAD2DEGF(primary ? ups->brush_rotation : ups->brush_rotation_sec)); - GPU_matrix_translate_2f(-x, -y); + GPU_matrix_translate_2f(-center[0], -center[1]); /* Scale based on tablet pressure. */ if (primary && ups->stroke_active && BKE_brush_use_size_pressure(brush)) { const float scale = ups->size_pressure_value; - GPU_matrix_translate_2f(x, y); + GPU_matrix_translate_2fv(center); GPU_matrix_scale_2f(scale, scale); - GPU_matrix_translate_2f(-x, -y); + GPU_matrix_translate_2f(-center[0], -center[1]); } if (ups->draw_anchored) { - quad.xmin = ups->anchored_initial_mouse[0] - ups->anchored_size; - quad.ymin = ups->anchored_initial_mouse[1] - ups->anchored_size; - quad.xmax = ups->anchored_initial_mouse[0] + ups->anchored_size; - quad.ymax = ups->anchored_initial_mouse[1] + ups->anchored_size; + quad.xmin = center[0] - ups->anchored_size; + quad.ymin = center[1] - ups->anchored_size; + quad.xmax = center[0] + ups->anchored_size; + quad.ymax = center[1] + ups->anchored_size; } else { const int radius = BKE_brush_size_get(vc->scene, brush) * zoom; - quad.xmin = x - radius; - quad.ymin = y - radius; - quad.xmax = x + radius; - quad.ymax = y + radius; + quad.xmin = center[0] - radius; + quad.ymin = center[1] - radius; + quad.xmax = center[0] + radius; + quad.ymax = center[1] + radius; } } else if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) { diff --git a/source/blender/editors/sculpt_paint/paint_image.cc b/source/blender/editors/sculpt_paint/paint_image.cc index 8c6358520ca..f334b2eb8f8 100644 --- a/source/blender/editors/sculpt_paint/paint_image.cc +++ b/source/blender/editors/sculpt_paint/paint_image.cc @@ -780,20 +780,7 @@ void ED_object_texture_paint_mode_enter_ex(Main *bmain, Scene *scene, Object *ob } if (ima) { - wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first); - LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { - const bScreen *screen = WM_window_get_active_screen(win); - LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { - SpaceLink *sl = static_cast<SpaceLink *>(area->spacedata.first); - if (sl->spacetype == SPACE_IMAGE) { - SpaceImage *sima = (SpaceImage *)sl; - - if (!sima->pin) { - ED_space_image_set(bmain, sima, ima, true); - } - } - } - } + ED_space_image_sync(bmain, ima, false); } ob->mode |= OB_MODE_TEXTURE_PAINT; diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 0c177fcb65f..47f1e7ec160 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -74,6 +74,7 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" +#include "ED_image.h" #include "ED_node.h" #include "ED_object.h" #include "ED_paint.h" @@ -6702,6 +6703,7 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op) BKE_texpaint_slot_refresh_cache(scene, ma, ob); BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_USER_NEW_IMAGE); WM_event_add_notifier(C, NC_IMAGE | NA_ADDED, ima); + ED_space_image_sync(bmain, ima, false); } if (layer) { BKE_texpaint_slot_refresh_cache(scene, ma, ob); diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index 97f5bd77d47..f1f864fdf82 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -249,7 +249,7 @@ static bool paint_stroke_use_scene_spacing(Brush *brush, ePaintMode mode) static bool paint_tool_raycast_original(Brush *brush, ePaintMode UNUSED(mode)) { - return brush->flag & BRUSH_ANCHORED; + return brush->flag & (BRUSH_ANCHORED | BRUSH_DRAG_DOT); } static bool paint_tool_require_inbetween_mouse_events(Brush *brush, ePaintMode mode) diff --git a/source/blender/editors/sculpt_paint/paint_vertex.cc b/source/blender/editors/sculpt_paint/paint_vertex.cc index e0509a795c7..f9f22173c05 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.cc +++ b/source/blender/editors/sculpt_paint/paint_vertex.cc @@ -1162,7 +1162,7 @@ static void do_weight_paint_vertex( } } -/* Toggle operator for turning vertex paint mode on or off (copied from sculpt.c) */ +/* Toggle operator for turning vertex paint mode on or off (copied from sculpt.cc) */ static void vertex_paint_init_session(Depsgraph *depsgraph, Scene *scene, Object *ob, @@ -2388,7 +2388,7 @@ static void wpaint_do_paint(bContext *C, WeightPaintInfo *wpi, Mesh *me, Brush *brush, - const char symm, + const ePaintSymmetryFlags symm, const int axis, const int i, const float angle) @@ -2415,7 +2415,7 @@ static void wpaint_do_radial_symmetry(bContext *C, WeightPaintInfo *wpi, Mesh *me, Brush *brush, - const char symm, + const ePaintSymmetryFlags symm, const int axis) { for (int i = 1; i < wp->radial_symm[axis - 'X']; i++) { @@ -2424,7 +2424,7 @@ static void wpaint_do_radial_symmetry(bContext *C, } } -/* near duplicate of: sculpt.c's, +/* near duplicate of: sculpt.cc's, * 'do_symmetrical_brush_actions' and 'vpaint_do_symmetrical_brush_actions'. */ static void wpaint_do_symmetrical_brush_actions( bContext *C, Object *ob, VPaint *wp, Sculpt *sd, WPaintData *wpd, WeightPaintInfo *wpi) @@ -2437,11 +2437,11 @@ static void wpaint_do_symmetrical_brush_actions( int i = 0; /* initial stroke */ - cache->mirror_symmetry_pass = 0; - wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'X', 0, 0); - wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'X'); - wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'Y'); - wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, 0, 'Z'); + cache->mirror_symmetry_pass = ePaintSymmetryFlags(0); + wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, ePaintSymmetryFlags(0), 'X', 0, 0); + wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, ePaintSymmetryFlags(0), 'X'); + wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, ePaintSymmetryFlags(0), 'Y'); + wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, ePaintSymmetryFlags(0), 'Z'); cache->symmetry = symm; @@ -2456,21 +2456,22 @@ static void wpaint_do_symmetrical_brush_actions( * X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */ for (i = 1; i <= symm; i++) { if (symm & i && (symm != 5 || i != 3) && (symm != 6 || !ELEM(i, 3, 5))) { - cache->mirror_symmetry_pass = i; + const ePaintSymmetryFlags symm = ePaintSymmetryFlags(i); + cache->mirror_symmetry_pass = symm; cache->radial_symmetry_pass = 0; - SCULPT_cache_calc_brushdata_symm(cache, i, 0, 0); + SCULPT_cache_calc_brushdata_symm(cache, symm, 0, 0); if (i & (1 << 0)) { - wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, i, 'X', 0, 0); - wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, i, 'X'); + wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, symm, 'X', 0, 0); + wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, symm, 'X'); } if (i & (1 << 1)) { - wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Y', 0, 0); - wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Y'); + wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, symm, 'Y', 0, 0); + wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, symm, 'Y'); } if (i & (1 << 2)) { - wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Z', 0, 0); - wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, i, 'Z'); + wpaint_do_paint(C, ob, wp, sd, wpd, wpi, me, brush, symm, 'Z', 0, 0); + wpaint_do_radial_symmetry(C, ob, wp, sd, wpd, wpi, me, brush, symm, 'Z'); } } } @@ -3738,7 +3739,7 @@ static void vpaint_do_paint(bContext *C, Object *ob, Mesh *me, Brush *brush, - const char symm, + const ePaintSymmetryFlags symm, const int axis, const int i, const float angle) @@ -3769,7 +3770,7 @@ static void vpaint_do_radial_symmetry(bContext *C, Object *ob, Mesh *me, Brush *brush, - const char symm, + const ePaintSymmetryFlags symm, const int axis) { for (int i = 1; i < vp->radial_symm[axis - 'X']; i++) { @@ -3778,7 +3779,7 @@ static void vpaint_do_radial_symmetry(bContext *C, } } -/* near duplicate of: sculpt.c's, +/* near duplicate of: sculpt.cc's, * 'do_symmetrical_brush_actions' and 'wpaint_do_symmetrical_brush_actions'. */ template<typename Color, typename Traits, eAttrDomain domain> static void vpaint_do_symmetrical_brush_actions( @@ -3792,11 +3793,15 @@ static void vpaint_do_symmetrical_brush_actions( int i = 0; /* initial stroke */ - cache->mirror_symmetry_pass = 0; - vpaint_do_paint<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'X', 0, 0); - vpaint_do_radial_symmetry<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'X'); - vpaint_do_radial_symmetry<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'Y'); - vpaint_do_radial_symmetry<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'Z'); + const ePaintSymmetryFlags initial_symm = ePaintSymmetryFlags(0); + cache->mirror_symmetry_pass = ePaintSymmetryFlags(0); + vpaint_do_paint<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, initial_symm, 'X', 0, 0); + vpaint_do_radial_symmetry<Color, Traits, domain>( + C, sd, vp, vpd, ob, me, brush, initial_symm, 'X'); + vpaint_do_radial_symmetry<Color, Traits, domain>( + C, sd, vp, vpd, ob, me, brush, initial_symm, 'Y'); + vpaint_do_radial_symmetry<Color, Traits, domain>( + C, sd, vp, vpd, ob, me, brush, initial_symm, 'Z'); cache->symmetry = symm; @@ -3804,21 +3809,28 @@ static void vpaint_do_symmetrical_brush_actions( * X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */ for (i = 1; i <= symm; i++) { if (symm & i && (symm != 5 || i != 3) && (symm != 6 || !ELEM(i, 3, 5))) { - cache->mirror_symmetry_pass = i; + const ePaintSymmetryFlags symm_pass = ePaintSymmetryFlags(i); + cache->mirror_symmetry_pass = symm_pass; cache->radial_symmetry_pass = 0; - SCULPT_cache_calc_brushdata_symm(cache, i, 0, 0); + SCULPT_cache_calc_brushdata_symm(cache, symm_pass, 0, 0); if (i & (1 << 0)) { - vpaint_do_paint<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'X', 0, 0); - vpaint_do_radial_symmetry<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'X'); + vpaint_do_paint<Color, Traits, domain>( + C, sd, vp, vpd, ob, me, brush, symm_pass, 'X', 0, 0); + vpaint_do_radial_symmetry<Color, Traits, domain>( + C, sd, vp, vpd, ob, me, brush, symm_pass, 'X'); } if (i & (1 << 1)) { - vpaint_do_paint<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'Y', 0, 0); - vpaint_do_radial_symmetry<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'Y'); + vpaint_do_paint<Color, Traits, domain>( + C, sd, vp, vpd, ob, me, brush, symm_pass, 'Y', 0, 0); + vpaint_do_radial_symmetry<Color, Traits, domain>( + C, sd, vp, vpd, ob, me, brush, symm_pass, 'Y'); } if (i & (1 << 2)) { - vpaint_do_paint<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'Z', 0, 0); - vpaint_do_radial_symmetry<Color, Traits, domain>(C, sd, vp, vpd, ob, me, brush, i, 'Z'); + vpaint_do_paint<Color, Traits, domain>( + C, sd, vp, vpd, ob, me, brush, symm_pass, 'Z', 0, 0); + vpaint_do_radial_symmetry<Color, Traits, domain>( + C, sd, vp, vpd, ob, me, brush, symm_pass, 'Z'); } } } 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 fca25ee2e4b..816e779cd06 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c +++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c @@ -587,6 +587,7 @@ typedef struct WPGradient_userData { Scene *scene; Mesh *me; MDeformVert *dvert; + const bool *select_vert; Brush *brush; const float *sco_start; /* [2] */ const float *sco_end; /* [2] */ @@ -683,7 +684,7 @@ static void gradientVertInit__mapFunc(void *userData, WPGradient_userData *grad_data = userData; WPGradient_vertStore *vs = &grad_data->vert_cache->elem[index]; - if (grad_data->use_select && !(grad_data->dvert[index].flag & SELECT)) { + if (grad_data->use_select && (grad_data->select_vert && !grad_data->select_vert[index])) { copy_v2_fl(vs->sco, FLT_MAX); return; } @@ -811,6 +812,8 @@ static int paint_weight_gradient_exec(bContext *C, wmOperator *op) data.scene = scene; data.me = ob->data; data.dvert = dverts; + data.select_vert = (const bool *)CustomData_get_layer_named( + &me->vdata, CD_PROP_BOOL, ".select_vert"); data.sco_start = sco_start; data.sco_end = sco_end; data.sco_line_div = 1.0f / len_v2v2(sco_start, sco_end); diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.cc index 6498d5f6281..3021e058719 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.cc @@ -6,6 +6,10 @@ * Implements the Sculpt Mode tools. */ +#include <cmath> +#include <cstdlib> +#include <cstring> + #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" @@ -65,10 +69,6 @@ #include "bmesh.h" -#include <math.h> -#include <stdlib.h> -#include <string.h> - /* -------------------------------------------------------------------- */ /** \name Sculpt PBVH Abstraction API * @@ -121,7 +121,7 @@ const float *SCULPT_vertex_co_get(SculptSession *ss, PBVHVertRef vertex) return CCG_elem_co(key, CCG_elem_offset(key, elem, vertex_index)); } } - return NULL; + return nullptr; } bool SCULPT_has_loop_colors(const Object *ob) @@ -209,9 +209,10 @@ void SCULPT_vertex_limit_surface_get(SculptSession *ss, PBVHVertRef vertex, floa const int grid_index = vertex.i / key->grid_area; const int vertex_index = vertex.i - grid_index * key->grid_area; - SubdivCCGCoord coord = {.grid_index = grid_index, - .x = vertex_index % key->grid_size, - .y = vertex_index / key->grid_size}; + SubdivCCGCoord coord{}; + coord.grid_index = grid_index; + coord.x = vertex_index % key->grid_size; + coord.y = vertex_index / key->grid_size; BKE_subdiv_ccg_eval_limit_point(ss->subdiv_ccg, &coord, r_co); break; } @@ -280,9 +281,9 @@ float (*SCULPT_mesh_deformed_positions_get(SculptSession *ss))[3] return ss->positions; case PBVH_BMESH: case PBVH_GRIDS: - return NULL; + return nullptr; } - return NULL; + return nullptr; } float *SCULPT_brush_deform_target_vertex_co_get(SculptSession *ss, @@ -351,7 +352,7 @@ bool SCULPT_vertex_visible_get(SculptSession *ss, PBVHVertRef vertex) switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: { const bool *hide_vert = BKE_pbvh_get_vert_hide(ss->pbvh); - return hide_vert == NULL || !hide_vert[vertex.i]; + return hide_vert == nullptr || !hide_vert[vertex.i]; } case PBVH_BMESH: return !BM_elem_flag_test((BMVert *)vertex.i, BM_ELEM_HIDDEN); @@ -370,8 +371,8 @@ bool SCULPT_vertex_visible_get(SculptSession *ss, PBVHVertRef vertex) void SCULPT_face_set_visibility_set(SculptSession *ss, int face_set, bool visible) { - BLI_assert(ss->face_sets != NULL); - BLI_assert(ss->hide_poly != NULL); + BLI_assert(ss->face_sets != nullptr); + BLI_assert(ss->hide_poly != nullptr); switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: case PBVH_GRIDS: @@ -389,8 +390,8 @@ void SCULPT_face_set_visibility_set(SculptSession *ss, int face_set, bool visibl void SCULPT_face_visibility_all_invert(SculptSession *ss) { - BLI_assert(ss->face_sets != NULL); - BLI_assert(ss->hide_poly != NULL); + BLI_assert(ss->face_sets != nullptr); + BLI_assert(ss->hide_poly != nullptr); switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: case PBVH_GRIDS: @@ -415,7 +416,7 @@ void SCULPT_face_visibility_all_set(SculptSession *ss, bool visible) switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: case PBVH_GRIDS: - BLI_assert(ss->hide_poly != NULL); + BLI_assert(ss->hide_poly != nullptr); memset(ss->hide_poly, !visible, sizeof(bool) * ss->totfaces); break; case PBVH_BMESH: { @@ -509,7 +510,7 @@ void SCULPT_vertex_face_set_set(SculptSession *ss, PBVHVertRef vertex, int face_ { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: { - BLI_assert(ss->face_sets != NULL); + BLI_assert(ss->face_sets != nullptr); const MeshElemMap *vert_map = &ss->pmap[vertex.i]; for (int j = 0; j < vert_map->count; j++) { const int poly_index = vert_map->indices[j]; @@ -524,7 +525,7 @@ void SCULPT_vertex_face_set_set(SculptSession *ss, PBVHVertRef vertex, int face_ case PBVH_BMESH: break; case PBVH_GRIDS: { - BLI_assert(ss->face_sets != NULL); + BLI_assert(ss->face_sets != nullptr); const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); const int grid_index = vertex.i / key->grid_area; const int face_index = BKE_subdiv_ccg_grid_to_face_index(ss->subdiv_ccg, grid_index); @@ -715,9 +716,10 @@ bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, PBVHVertRef vertex) const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); const int grid_index = vertex.i / key->grid_area; const int vertex_index = vertex.i - grid_index * key->grid_area; - const SubdivCCGCoord coord = {.grid_index = grid_index, - .x = vertex_index % key->grid_size, - .y = vertex_index / key->grid_size}; + SubdivCCGCoord coord{}; + coord.grid_index = grid_index; + coord.x = vertex_index % key->grid_size; + coord.y = vertex_index / key->grid_size; int v1, v2; const SubdivCCGAdjacencyType adjacency = BKE_subdiv_ccg_coarse_mesh_adjacency_info_get( ss->subdiv_ccg, &coord, ss->mloop, ss->mpoly, &v1, &v2); @@ -775,21 +777,23 @@ static void sculpt_vertex_neighbor_add(SculptVertexNeighborIter *iter, iter->capacity += SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY; if (iter->neighbors == iter->neighbors_fixed) { - iter->neighbors = MEM_mallocN(iter->capacity * sizeof(PBVHVertRef), "neighbor array"); + iter->neighbors = static_cast<PBVHVertRef *>( + MEM_mallocN(iter->capacity * sizeof(PBVHVertRef), "neighbor array")); memcpy(iter->neighbors, iter->neighbors_fixed, sizeof(PBVHVertRef) * iter->size); } else { - iter->neighbors = MEM_reallocN_id( - iter->neighbors, iter->capacity * sizeof(PBVHVertRef), "neighbor array"); + iter->neighbors = static_cast<PBVHVertRef *>(MEM_reallocN_id( + iter->neighbors, iter->capacity * sizeof(PBVHVertRef), "neighbor array")); } if (iter->neighbor_indices == iter->neighbor_indices_fixed) { - iter->neighbor_indices = MEM_mallocN(iter->capacity * sizeof(int), "neighbor array"); + iter->neighbor_indices = static_cast<int *>( + MEM_mallocN(iter->capacity * sizeof(int), "neighbor array")); memcpy(iter->neighbor_indices, iter->neighbor_indices_fixed, sizeof(int) * iter->size); } else { - iter->neighbor_indices = MEM_reallocN_id( - iter->neighbor_indices, iter->capacity * sizeof(int), "neighbor array"); + iter->neighbor_indices = static_cast<int *>( + MEM_reallocN_id(iter->neighbor_indices, iter->capacity * sizeof(int), "neighbor array")); } } @@ -849,7 +853,7 @@ static void sculpt_vertex_neighbors_get_faces(SculptSession *ss, } if (ss->fake_neighbors.use_fake_neighbors) { - BLI_assert(ss->fake_neighbors.fake_neighbor_index != NULL); + BLI_assert(ss->fake_neighbors.fake_neighbor_index != nullptr); if (ss->fake_neighbors.fake_neighbor_index[vertex.i] != FAKE_NEIGHBOR_NONE) { sculpt_vertex_neighbor_add( iter, @@ -871,9 +875,10 @@ static void sculpt_vertex_neighbors_get_grids(SculptSession *ss, const int grid_index = vertex.i / key->grid_area; const int vertex_index = vertex.i - grid_index * key->grid_area; - SubdivCCGCoord coord = {.grid_index = grid_index, - .x = vertex_index % key->grid_size, - .y = vertex_index / key->grid_size}; + SubdivCCGCoord coord{}; + coord.grid_index = grid_index; + coord.x = vertex_index % key->grid_size; + coord.y = vertex_index / key->grid_size; SubdivCCGNeighbors neighbors; BKE_subdiv_ccg_neighbor_coords_get(ss->subdiv_ccg, &coord, include_duplicates, &neighbors); @@ -892,7 +897,7 @@ static void sculpt_vertex_neighbors_get_grids(SculptSession *ss, } if (ss->fake_neighbors.use_fake_neighbors) { - BLI_assert(ss->fake_neighbors.fake_neighbor_index != NULL); + BLI_assert(ss->fake_neighbors.fake_neighbor_index != nullptr); if (ss->fake_neighbors.fake_neighbor_index[vertex.i] != FAKE_NEIGHBOR_NONE) { int v = ss->fake_neighbors.fake_neighbor_index[vertex.i]; sculpt_vertex_neighbor_add(iter, BKE_pbvh_make_vref(v), v); @@ -946,9 +951,10 @@ bool SCULPT_vertex_is_boundary(const SculptSession *ss, const PBVHVertRef vertex const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); const int grid_index = vertex.i / key->grid_area; const int vertex_index = vertex.i - grid_index * key->grid_area; - const SubdivCCGCoord coord = {.grid_index = grid_index, - .x = vertex_index % key->grid_size, - .y = vertex_index / key->grid_size}; + SubdivCCGCoord coord{}; + coord.grid_index = grid_index; + coord.x = vertex_index % key->grid_size; + coord.y = vertex_index / key->grid_size; int v1, v2; const SubdivCCGAdjacencyType adjacency = BKE_subdiv_ccg_coarse_mesh_adjacency_info_get( ss->subdiv_ccg, &coord, ss->mloop, ss->mpoly, &v1, &v2); @@ -1005,18 +1011,18 @@ bool SCULPT_check_vertex_pivot_symmetry(const float vco[3], const float pco[3], return is_in_symmetry_area; } -typedef struct NearestVertexTLSData { +struct NearestVertexTLSData { PBVHVertRef nearest_vertex; float nearest_vertex_distance_squared; -} NearestVertexTLSData; +}; static void do_nearest_vertex_get_task_cb(void *__restrict userdata, const int n, const TaskParallelTLS *__restrict tls) { - SculptThreadedTaskData *data = userdata; + SculptThreadedTaskData *data = static_cast<SculptThreadedTaskData *>(userdata); SculptSession *ss = data->ob->sculpt; - NearestVertexTLSData *nvtd = tls->userdata_chunk; + NearestVertexTLSData *nvtd = static_cast<NearestVertexTLSData *>(tls->userdata_chunk); PBVHVertexIter vd; BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -1030,12 +1036,12 @@ static void do_nearest_vertex_get_task_cb(void *__restrict userdata, BKE_pbvh_vertex_iter_end; } -static void nearest_vertex_get_reduce(const void *__restrict UNUSED(userdata), +static void nearest_vertex_get_reduce(const void *__restrict /*userdata*/, void *__restrict chunk_join, void *__restrict chunk) { - NearestVertexTLSData *join = chunk_join; - NearestVertexTLSData *nvtd = chunk; + NearestVertexTLSData *join = static_cast<NearestVertexTLSData *>(chunk_join); + NearestVertexTLSData *nvtd = static_cast<NearestVertexTLSData *>(chunk); if (join->nearest_vertex.i == PBVH_REF_NONE) { join->nearest_vertex = nvtd->nearest_vertex; join->nearest_vertex_distance_squared = nvtd->nearest_vertex_distance_squared; @@ -1050,26 +1056,24 @@ PBVHVertRef SCULPT_nearest_vertex_get( Sculpt *sd, Object *ob, const float co[3], float max_distance, bool use_original) { SculptSession *ss = ob->sculpt; - PBVHNode **nodes = NULL; + PBVHNode **nodes = nullptr; int totnode; - SculptSearchSphereData data = { - .ss = ss, - .sd = sd, - .radius_squared = max_distance * max_distance, - .original = use_original, - .center = co, - }; + SculptSearchSphereData data{}; + data.sd = sd; + data.radius_squared = max_distance * max_distance; + data.original = use_original; + data.center = co; + BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, &totnode); if (totnode == 0) { return BKE_pbvh_make_vref(PBVH_REF_NONE); } - SculptThreadedTaskData task_data = { - .sd = sd, - .ob = ob, - .nodes = nodes, - .max_distance_squared = max_distance * max_distance, - }; + SculptThreadedTaskData task_data{}; + task_data.sd = sd; + task_data.ob = ob; + task_data.nodes = nodes; + task_data.max_distance_squared = max_distance * max_distance; copy_v3_v3(task_data.nearest_vertex_search_co, co); NearestVertexTLSData nvtd; @@ -1103,7 +1107,7 @@ bool SCULPT_is_vertex_inside_brush_radius_symm(const float vertex[3], continue; } float location[3]; - flip_v3_v3(location, br_co, (char)i); + flip_v3_v3(location, br_co, ePaintSymmetryFlags(i)); if (len_squared_v3v3(location, vertex) < radius * radius) { return true; } @@ -1176,7 +1180,7 @@ void SCULPT_floodfill_add_initial_with_symmetry(Sculpt *sd, else if (radius > 0.0f) { float radius_squared = (radius == FLT_MAX) ? FLT_MAX : radius * radius; float location[3]; - flip_v3_v3(location, SCULPT_vertex_co_get(ss, vertex), i); + flip_v3_v3(location, SCULPT_vertex_co_get(ss, vertex), ePaintSymmetryFlags(i)); v = SCULPT_nearest_vertex_get(sd, ob, location, radius_squared, false); } @@ -1203,7 +1207,7 @@ void SCULPT_floodfill_add_active( } else if (radius > 0.0f) { float location[3]; - flip_v3_v3(location, SCULPT_active_vertex_co_get(ss), i); + flip_v3_v3(location, SCULPT_active_vertex_co_get(ss), ePaintSymmetryFlags(i)); v = SCULPT_nearest_vertex_get(sd, ob, location, radius, false); } @@ -1253,7 +1257,7 @@ void SCULPT_floodfill_free(SculptFloodFill *flood) { MEM_SAFE_FREE(flood->visited_verts); BLI_gsqueue_free(flood->queue); - flood->queue = NULL; + flood->queue = nullptr; } /** \} */ @@ -1302,7 +1306,7 @@ static bool sculpt_tool_is_proxy_used(const char sculpt_tool) static bool sculpt_brush_use_topology_rake(const SculptSession *ss, const Brush *brush) { return SCULPT_TOOL_HAS_TOPOLOGY_RAKE(brush->sculpt_tool) && - (brush->topology_rake_factor > 0.0f) && (ss->bm != NULL); + (brush->topology_rake_factor > 0.0f) && (ss->bm != nullptr); } /** @@ -1340,11 +1344,11 @@ static bool sculpt_brush_needs_rake_rotation(const Brush *brush) /** \name Sculpt Init/Update * \{ */ -typedef enum StrokeFlags { +enum StrokeFlags { CLIP_X = 1, CLIP_Y = 2, CLIP_Z = 4, -} StrokeFlags; +}; void SCULPT_orig_vert_data_unode_init(SculptOrigVertData *data, Object *ob, SculptUndoNode *unode) { @@ -1399,7 +1403,7 @@ void SCULPT_orig_vert_data_update(SculptOrigVertData *orig_data, PBVHVertexIter } } -static void sculpt_rake_data_update(struct SculptRakeData *srd, const float co[3]) +static void sculpt_rake_data_update(SculptRakeData *srd, const float co[3]) { float rake_dist = len_v3v3(srd->follow_co, co); if (rake_dist > srd->follow_dist) { @@ -1434,9 +1438,9 @@ bool SCULPT_stroke_is_dynamic_topology(const SculptSession *ss, const Brush *bru static void paint_mesh_restore_co_task_cb(void *__restrict userdata, const int n, - const TaskParallelTLS *__restrict UNUSED(tls)) + const TaskParallelTLS *__restrict /*tls*/) { - SculptThreadedTaskData *data = userdata; + SculptThreadedTaskData *data = static_cast<SculptThreadedTaskData *>(userdata); SculptSession *ss = data->ob->sculpt; SculptUndoNode *unode; @@ -1518,19 +1522,18 @@ static void paint_mesh_restore_co(Sculpt *sd, Object *ob) PBVHNode **nodes; int totnode; - BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); + BKE_pbvh_search_gather(ss->pbvh, nullptr, nullptr, &nodes, &totnode); /** * Disable multi-threading when dynamic-topology is enabled. Otherwise, * new entries might be inserted by #SCULPT_undo_push_node() into the #GHash * used internally by #BM_log_original_vert_co() by a different thread. See T33787. */ - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - }; + SculptThreadedTaskData data{}; + data.sd = sd; + data.ob = ob; + data.brush = brush; + data.nodes = nodes; TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true && !ss->bm, totnode); @@ -1624,7 +1627,7 @@ void SCULPT_brush_test_init(SculptSession *ss, SculptBrushTest *test) } else { copy_v3_v3(test->location, ss->cursor_location); - test->mirror_symmetry_pass = 0; + test->mirror_symmetry_pass = ePaintSymmetryFlags(0); test->radial_symmetry_pass = 0; unit_m4(test->symm_rot_mat_inv); } @@ -1640,7 +1643,7 @@ void SCULPT_brush_test_init(SculptSession *ss, SculptBrushTest *test) test->clip_rv3d = rv3d; } else { - test->clip_rv3d = NULL; + test->clip_rv3d = nullptr; } } @@ -1837,7 +1840,10 @@ static bool sculpt_brush_test_cyl(SculptBrushTest *test, /* ===== Sculpting ===== */ -static float calc_overlap(StrokeCache *cache, const char symm, const char axis, const float angle) +static float calc_overlap(StrokeCache *cache, + const ePaintSymmetryFlags symm, + const char axis, + const float angle) { float mirror[3]; float distsq; @@ -1860,7 +1866,7 @@ static float calc_overlap(StrokeCache *cache, const char symm, const char axis, static float calc_radial_symmetry_feather(Sculpt *sd, StrokeCache *cache, - const char symm, + const ePaintSymmetryFlags symm, const char axis) { float overlap = 0.0f; @@ -1887,11 +1893,11 @@ static float calc_symmetry_feather(Sculpt *sd, StrokeCache *cache) continue; } - overlap += calc_overlap(cache, i, 0, 0); + overlap += calc_overlap(cache, ePaintSymmetryFlags(i), 0, 0); - overlap += calc_radial_symmetry_feather(sd, cache, i, 'X'); - overlap += calc_radial_symmetry_feather(sd, cache, i, 'Y'); - overlap += calc_radial_symmetry_feather(sd, cache, i, 'Z'); + overlap += calc_radial_symmetry_feather(sd, cache, ePaintSymmetryFlags(i), 'X'); + overlap += calc_radial_symmetry_feather(sd, cache, ePaintSymmetryFlags(i), 'Y'); + overlap += calc_radial_symmetry_feather(sd, cache, ePaintSymmetryFlags(i), 'Z'); } return 1.0f / overlap; } @@ -1912,26 +1918,26 @@ static float calc_symmetry_feather(Sculpt *sd, StrokeCache *cache) * \note These are all _very_ similar, when changing one, check others. * \{ */ -typedef struct AreaNormalCenterTLSData { +struct AreaNormalCenterTLSData { /* 0 = towards view, 1 = flipped */ float area_cos[2][3]; float area_nos[2][3]; int count_no[2]; int count_co[2]; -} AreaNormalCenterTLSData; +}; static void calc_area_normal_and_center_task_cb(void *__restrict userdata, const int n, const TaskParallelTLS *__restrict tls) { - SculptThreadedTaskData *data = userdata; + SculptThreadedTaskData *data = static_cast<SculptThreadedTaskData *>(userdata); SculptSession *ss = data->ob->sculpt; - AreaNormalCenterTLSData *anctd = tls->userdata_chunk; + AreaNormalCenterTLSData *anctd = static_cast<AreaNormalCenterTLSData *>(tls->userdata_chunk); const bool use_area_nos = data->use_area_nos; const bool use_area_cos = data->use_area_cos; PBVHVertexIter vd; - SculptUndoNode *unode = NULL; + SculptUndoNode *unode = nullptr; bool use_original = false; bool normal_test_r, area_test_r; @@ -1982,7 +1988,8 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata, int(*orco_tris)[3]; int orco_tris_num; - BKE_pbvh_node_get_bm_orco_data(data->nodes[n], &orco_tris, &orco_tris_num, &orco_coords, NULL); + BKE_pbvh_node_get_bm_orco_data( + data->nodes[n], &orco_tris, &orco_tris_num, &orco_coords, nullptr); for (int i = 0; i < orco_tris_num; i++) { const float *co_tri[3] = { @@ -2109,12 +2116,12 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata, } } -static void calc_area_normal_and_center_reduce(const void *__restrict UNUSED(userdata), +static void calc_area_normal_and_center_reduce(const void *__restrict /*userdata*/, void *__restrict chunk_join, void *__restrict chunk) { - AreaNormalCenterTLSData *join = chunk_join; - AreaNormalCenterTLSData *anctd = chunk; + AreaNormalCenterTLSData *join = static_cast<AreaNormalCenterTLSData *>(chunk_join); + AreaNormalCenterTLSData *anctd = static_cast<AreaNormalCenterTLSData *>(chunk); /* For flatten center. */ add_v3_v3(join->area_cos[0], anctd->area_cos[0]); @@ -2137,16 +2144,15 @@ void SCULPT_calc_area_center( const bool has_bm_orco = ss->bm && SCULPT_stroke_is_dynamic_topology(ss, brush); int n; - /* Intentionally set 'sd' to NULL since we share logic with vertex paint. */ - SculptThreadedTaskData data = { - .sd = NULL, - .ob = ob, - .brush = brush, - .nodes = nodes, - .totnode = totnode, - .has_bm_orco = has_bm_orco, - .use_area_cos = true, - }; + /* Intentionally set 'sd' to nullptr since we share logic with vertex paint. */ + SculptThreadedTaskData data{}; + data.sd = nullptr; + data.ob = ob; + data.brush = brush; + data.nodes = nodes; + data.totnode = totnode; + data.has_bm_orco = has_bm_orco; + data.use_area_cos = true; AreaNormalCenterTLSData anctd = {{{0}}}; @@ -2195,17 +2201,16 @@ bool SCULPT_pbvh_calc_area_normal(const Brush *brush, SculptSession *ss = ob->sculpt; const bool has_bm_orco = ss->bm && SCULPT_stroke_is_dynamic_topology(ss, brush); - /* Intentionally set 'sd' to NULL since this is used for vertex paint too. */ - SculptThreadedTaskData data = { - .sd = NULL, - .ob = ob, - .brush = brush, - .nodes = nodes, - .totnode = totnode, - .has_bm_orco = has_bm_orco, - .use_area_nos = true, - .any_vertex_sampled = false, - }; + /* Intentionally set 'sd' to nullptr since this is used for vertex paint too. */ + SculptThreadedTaskData data{}; + data.sd = nullptr; + data.ob = ob; + data.brush = brush; + data.nodes = nodes; + data.totnode = totnode; + data.has_bm_orco = has_bm_orco; + data.use_area_nos = true; + data.any_vertex_sampled = false; AreaNormalCenterTLSData anctd = {{{0}}}; @@ -2234,17 +2239,16 @@ void SCULPT_calc_area_normal_and_center( const bool has_bm_orco = ss->bm && SCULPT_stroke_is_dynamic_topology(ss, brush); int n; - /* Intentionally set 'sd' to NULL since this is used for vertex paint too. */ - SculptThreadedTaskData data = { - .sd = NULL, - .ob = ob, - .brush = brush, - .nodes = nodes, - .totnode = totnode, - .has_bm_orco = has_bm_orco, - .use_area_cos = true, - .use_area_nos = true, - }; + /* Intentionally set 'sd' to nullptr since this is used for vertex paint too. */ + SculptThreadedTaskData data{}; + data.sd = nullptr; + data.ob = ob; + data.brush = brush; + data.nodes = nodes; + data.totnode = totnode; + data.has_bm_orco = has_bm_orco; + data.use_area_cos = true; + data.use_area_nos = true; AreaNormalCenterTLSData anctd = {{{0}}}; @@ -2298,7 +2302,7 @@ static float brush_strength(const Sculpt *sd, const StrokeCache *cache, const float feather, const UnifiedPaintSettings *ups, - const PaintModeSettings *UNUSED(paint_mode_settings)) + const PaintModeSettings * /*paint_mode_settings*/) { const Scene *scene = cache->vc->scene; const Brush *brush = BKE_paint_brush((Paint *)&sd->paint); @@ -2545,7 +2549,7 @@ float SCULPT_brush_strength_factor(SculptSession *ss, bool SCULPT_search_sphere_cb(PBVHNode *node, void *data_v) { - SculptSearchSphereData *data = data_v; + SculptSearchSphereData *data = static_cast<SculptSearchSphereData *>(data_v); const float *center; float nearest[3]; if (data->center) { @@ -2591,7 +2595,7 @@ bool SCULPT_search_sphere_cb(PBVHNode *node, void *data_v) bool SCULPT_search_circle_cb(PBVHNode *node, void *data_v) { - SculptSearchCircleData *data = data_v; + SculptSearchCircleData *data = static_cast<SculptSearchCircleData *>(data_v); float bb_min[3], bb_max[3]; if (data->ignore_fully_ineffective) { @@ -2653,15 +2657,14 @@ static PBVHNode **sculpt_pbvh_gather_cursor_update(Object *ob, int *r_totnode) { SculptSession *ss = ob->sculpt; - PBVHNode **nodes = NULL; - SculptSearchSphereData data = { - .ss = ss, - .sd = sd, - .radius_squared = ss->cursor_radius, - .original = use_original, - .ignore_fully_ineffective = false, - .center = NULL, - }; + PBVHNode **nodes = nullptr; + SculptSearchSphereData data{}; + data.ss = ss; + data.sd = sd; + data.radius_squared = ss->cursor_radius; + data.original = use_original; + data.ignore_fully_ineffective = false; + data.center = nullptr; BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, r_totnode); return nodes; } @@ -2674,34 +2677,32 @@ static PBVHNode **sculpt_pbvh_gather_generic(Object *ob, int *r_totnode) { SculptSession *ss = ob->sculpt; - PBVHNode **nodes = NULL; + PBVHNode **nodes = nullptr; /* Build a list of all nodes that are potentially within the cursor or brush's area of influence. */ if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) { - SculptSearchSphereData data = { - .ss = ss, - .sd = sd, - .radius_squared = square_f(ss->cache->radius * radius_scale), - .original = use_original, - .ignore_fully_ineffective = brush->sculpt_tool != SCULPT_TOOL_MASK, - .center = NULL, - }; + SculptSearchSphereData data{}; + data.ss = ss; + data.sd = sd; + data.radius_squared = square_f(ss->cache->radius * radius_scale); + data.original = use_original; + data.ignore_fully_ineffective = brush->sculpt_tool != SCULPT_TOOL_MASK; + data.center = nullptr; BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, r_totnode); } else { - struct DistRayAABB_Precalc dist_ray_to_aabb_precalc; + DistRayAABB_Precalc dist_ray_to_aabb_precalc; dist_squared_ray_to_aabb_v3_precalc( &dist_ray_to_aabb_precalc, ss->cache->location, ss->cache->view_normal); - SculptSearchCircleData data = { - .ss = ss, - .sd = sd, - .radius_squared = ss->cache ? square_f(ss->cache->radius * radius_scale) : - ss->cursor_radius, - .original = use_original, - .dist_ray_to_aabb_precalc = &dist_ray_to_aabb_precalc, - .ignore_fully_ineffective = brush->sculpt_tool != SCULPT_TOOL_MASK, - }; + SculptSearchCircleData data{}; + data.ss = ss; + data.sd = sd; + data.radius_squared = ss->cache ? square_f(ss->cache->radius * radius_scale) : + ss->cursor_radius; + data.original = use_original; + data.dist_ray_to_aabb_precalc = &dist_ray_to_aabb_precalc; + data.ignore_fully_ineffective = brush->sculpt_tool != SCULPT_TOOL_MASK; BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_circle_cb, &data, &nodes, r_totnode); } return nodes; @@ -2899,7 +2900,7 @@ static void sculpt_pbvh_update_pixels(PaintModeSettings *paint_mode_settings, /** \name Generic Brush Plane & Symmetry Utilities * \{ */ -typedef struct { +struct SculptRaycastData { SculptSession *ss; const float *ray_start; const float *ray_normal; @@ -2912,21 +2913,21 @@ typedef struct { int active_face_grid_index; - struct IsectRayPrecalc isect_precalc; -} SculptRaycastData; + IsectRayPrecalc isect_precalc; +}; -typedef struct { +struct SculptFindNearestToRayData { SculptSession *ss; const float *ray_start, *ray_normal; bool hit; float depth; float dist_sq_to_ray; bool original; -} SculptFindNearestToRayData; +}; ePaintSymmetryAreas SCULPT_get_vertex_symm_area(const float co[3]) { - ePaintSymmetryAreas symm_area = PAINT_SYMM_AREA_DEFAULT; + ePaintSymmetryAreas symm_area = ePaintSymmetryAreas(PAINT_SYMM_AREA_DEFAULT); if (co[0] < 0.0f) { symm_area |= PAINT_SYMM_AREA_X; } @@ -2945,7 +2946,7 @@ void SCULPT_flip_v3_by_symm_area(float v[3], const float pivot[3]) { for (int i = 0; i < 3; i++) { - ePaintSymmetryFlags symm_it = 1 << i; + ePaintSymmetryFlags symm_it = ePaintSymmetryFlags(1 << i); if (!(symm & symm_it)) { continue; } @@ -2964,7 +2965,7 @@ void SCULPT_flip_quat_by_symm_area(float quat[4], const float pivot[3]) { for (int i = 0; i < 3; i++) { - ePaintSymmetryFlags symm_it = 1 << i; + ePaintSymmetryFlags symm_it = ePaintSymmetryFlags(1 << i); if (!(symm & symm_it)) { continue; } @@ -3101,7 +3102,7 @@ static void do_gravity_task_cb_ex(void *__restrict userdata, const int n, const TaskParallelTLS *__restrict tls) { - SculptThreadedTaskData *data = userdata; + SculptThreadedTaskData *data = static_cast<SculptThreadedTaskData *>(userdata); SculptSession *ss = data->ob->sculpt; const Brush *brush = data->brush; float *offset = data->offset; @@ -3129,7 +3130,7 @@ static void do_gravity_task_cb_ex(void *__restrict userdata, vd.mask ? *vd.mask : 0.0f, vd.vertex, thread_id, - NULL); + nullptr); mul_v3_v3fl(proxy[vd.i], offset, fade); @@ -3155,13 +3156,12 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl mul_v3_fl(offset, bstrength); /* Threaded loop over nodes. */ - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .offset = offset, - }; + SculptThreadedTaskData data{}; + data.sd = sd; + data.ob = ob; + data.brush = brush; + data.nodes = nodes; + data.offset = offset; TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); @@ -3177,10 +3177,9 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl void SCULPT_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3]) { Mesh *me = (Mesh *)ob->data; - float(*ofs)[3] = NULL; + float(*ofs)[3] = nullptr; int a; const int kb_act_idx = ob->shapenr - 1; - KeyBlock *currkey; /* For relative keys editing of base should update other keys. */ if (BKE_keyblock_is_basis(me->key, kb_act_idx)) { @@ -3192,7 +3191,7 @@ void SCULPT_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3]) } /* Apply offsets on other keys. */ - for (currkey = me->key->block.first; currkey; currkey = currkey->next) { + LISTBASE_FOREACH (KeyBlock *, currkey, &me->key->block) { if ((currkey != kb) && (currkey->relative == kb_act_idx)) { BKE_keyblock_update_from_offset(ob, currkey, ofs); } @@ -3216,8 +3215,8 @@ void SCULPT_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3]) static void sculpt_topology_update(Sculpt *sd, Object *ob, Brush *brush, - UnifiedPaintSettings *UNUSED(ups), - PaintModeSettings *UNUSED(paint_mode_settings)) + UnifiedPaintSettings * /*ups*/, + PaintModeSettings * /*paint_mode_settings*/) { SculptSession *ss = ob->sculpt; @@ -3239,7 +3238,7 @@ static void sculpt_topology_update(Sculpt *sd, MEM_SAFE_FREE(ss->vertex_info.boundary); MEM_SAFE_FREE(ss->vertex_info.connected_component); - PBVHTopologyUpdateMode mode = 0; + PBVHTopologyUpdateMode mode = PBVHTopologyUpdateMode(0); float location[3]; if (!(sd->flags & SCULPT_DYNTOPO_DETAIL_MANUAL)) { @@ -3284,9 +3283,9 @@ static void sculpt_topology_update(Sculpt *sd, static void do_brush_action_task_cb(void *__restrict userdata, const int n, - const TaskParallelTLS *__restrict UNUSED(tls)) + const TaskParallelTLS *__restrict /*tls*/) { - SculptThreadedTaskData *data = userdata; + SculptThreadedTaskData *data = static_cast<SculptThreadedTaskData *>(userdata); SculptSession *ss = data->ob->sculpt; bool need_coords = ss->cache->supports_gravity; @@ -3342,7 +3341,7 @@ static void do_brush_action(Sculpt *sd, if (SCULPT_tool_needs_all_pbvh_nodes(brush)) { /* These brushes need to update all nodes as they are not constrained by the brush radius */ - BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); + BKE_pbvh_search_gather(ss->pbvh, nullptr, nullptr, &nodes, &totnode); } else if (brush->sculpt_tool == SCULPT_TOOL_CLOTH) { nodes = SCULPT_cloth_brush_affected_nodes_gather(ss, brush, &totnode); @@ -3380,7 +3379,7 @@ static void do_brush_action(Sculpt *sd, /* TODO(pablodp606): This check should be done in the undo code and not here, but the rest of * the sculpt code is not checking for unsupported undo types that may return a null node. */ if (BKE_pbvh_type(ss->pbvh) != PBVH_BMESH) { - SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_FACE_SETS); + SCULPT_undo_push_node(ob, nullptr, SCULPT_UNDO_FACE_SETS); } if (ss->cache->invert) { @@ -3407,9 +3406,9 @@ static void do_brush_action(Sculpt *sd, /* Initialize surface smooth cache. */ if ((brush->sculpt_tool == SCULPT_TOOL_SMOOTH) && (brush->smooth_deform_type == BRUSH_SMOOTH_DEFORM_SURFACE)) { - BLI_assert(ss->cache->surface_smooth_laplacian_disp == NULL); - ss->cache->surface_smooth_laplacian_disp = MEM_callocN( - sizeof(float[3]) * SCULPT_vertex_count_get(ss), "HC smooth laplacian b"); + BLI_assert(ss->cache->surface_smooth_laplacian_disp == nullptr); + ss->cache->surface_smooth_laplacian_disp = static_cast<float(*)[3]>( + MEM_callocN(sizeof(float[3]) * SCULPT_vertex_count_get(ss), "HC smooth laplacian b")); } } } @@ -3421,12 +3420,11 @@ static void do_brush_action(Sculpt *sd, float location[3]; if (!use_pixels) { - SculptThreadedTaskData task_data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - }; + SculptThreadedTaskData task_data{}; + task_data.sd = sd; + task_data.ob = ob; + task_data.brush = brush; + task_data.nodes = nodes; TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); @@ -3622,7 +3620,7 @@ static void do_brush_action(Sculpt *sd, static void sculpt_flush_pbvhvert_deform(Object *ob, PBVHVertexIter *vd) { SculptSession *ss = ob->sculpt; - Mesh *me = ob->data; + Mesh *me = static_cast<Mesh *>(ob->data); float disp[3], newco[3]; int index = vd->vert_indices[vd->i]; @@ -3641,9 +3639,9 @@ static void sculpt_flush_pbvhvert_deform(Object *ob, PBVHVertexIter *vd) static void sculpt_combine_proxies_task_cb(void *__restrict userdata, const int n, - const TaskParallelTLS *__restrict UNUSED(tls)) + const TaskParallelTLS *__restrict /*tls*/) { - SculptThreadedTaskData *data = userdata; + SculptThreadedTaskData *data = static_cast<SculptThreadedTaskData *>(userdata); SculptSession *ss = data->ob->sculpt; Sculpt *sd = data->sd; Object *ob = data->ob; @@ -3652,7 +3650,7 @@ static void sculpt_combine_proxies_task_cb(void *__restrict userdata, PBVHVertexIter vd; PBVHProxyNode *proxies; int proxy_count; - float(*orco)[3] = NULL; + float(*orco)[3] = nullptr; if (use_orco && !ss->bm) { orco = SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COORDS)->co; @@ -3713,13 +3711,12 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob) BKE_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode); - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .use_proxies_orco = use_orco, - }; + SculptThreadedTaskData data{}; + data.sd = sd; + data.ob = ob; + data.brush = brush; + data.nodes = nodes; + data.use_proxies_orco = use_orco; TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); @@ -3734,12 +3731,11 @@ void SCULPT_combine_transform_proxies(Sculpt *sd, Object *ob) int totnode; BKE_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode); - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .nodes = nodes, - .use_proxies_orco = false, - }; + SculptThreadedTaskData data{}; + data.sd = sd; + data.ob = ob; + data.nodes = nodes; + data.use_proxies_orco = false; TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); @@ -3778,9 +3774,9 @@ static void sculpt_update_keyblock(Object *ob) static void SCULPT_flush_stroke_deform_task_cb(void *__restrict userdata, const int n, - const TaskParallelTLS *__restrict UNUSED(tls)) + const TaskParallelTLS *__restrict /*tls*/) { - SculptThreadedTaskData *data = userdata; + SculptThreadedTaskData *data = static_cast<SculptThreadedTaskData *>(userdata); SculptSession *ss = data->ob->sculpt; Object *ob = data->ob; float(*vertCos)[3] = data->vertCos; @@ -3812,25 +3808,25 @@ void SCULPT_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_used) int totnode; Mesh *me = (Mesh *)ob->data; PBVHNode **nodes; - float(*vertCos)[3] = NULL; + float(*vertCos)[3] = nullptr; if (ss->shapekey_active) { - vertCos = MEM_mallocN(sizeof(*vertCos) * me->totvert, "flushStrokeDeofrm keyVerts"); + vertCos = static_cast<float(*)[3]>( + MEM_mallocN(sizeof(*vertCos) * me->totvert, "flushStrokeDeofrm keyVerts")); /* Mesh could have isolated verts which wouldn't be in BVH, to deal with this we copy old * coordinates over new ones and then update coordinates for all vertices from BVH. */ memcpy(vertCos, ss->orig_cos, sizeof(*vertCos) * me->totvert); } - BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); + BKE_pbvh_search_gather(ss->pbvh, nullptr, nullptr, &nodes, &totnode); - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .vertCos = vertCos, - }; + SculptThreadedTaskData data{}; + data.sd = sd; + data.ob = ob; + data.brush = brush; + data.nodes = nodes; + data.vertCos = vertCos; TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); @@ -3849,7 +3845,7 @@ void SCULPT_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_used) } void SCULPT_cache_calc_brushdata_symm(StrokeCache *cache, - const char symm, + const ePaintSymmetryFlags symm, const char axis, const float angle) { @@ -3899,11 +3895,11 @@ void SCULPT_cache_calc_brushdata_symm(StrokeCache *cache, } } -typedef void (*BrushActionFunc)(Sculpt *sd, - Object *ob, - Brush *brush, - UnifiedPaintSettings *ups, - PaintModeSettings *paint_mode_settings); +using BrushActionFunc = void (*)(Sculpt *sd, + Object *ob, + Brush *brush, + UnifiedPaintSettings *ups, + PaintModeSettings *paint_mode_settings); static void do_tiled(Sculpt *sd, Object *ob, @@ -3975,9 +3971,9 @@ static void do_radial_symmetry(Sculpt *sd, UnifiedPaintSettings *ups, PaintModeSettings *paint_mode_settings, BrushActionFunc action, - const char symm, + const ePaintSymmetryFlags symm, const int axis, - const float UNUSED(feather)) + const float /*feather*/) { SculptSession *ss = ob->sculpt; @@ -4026,15 +4022,16 @@ static void do_symmetrical_brush_actions(Sculpt *sd, if (!SCULPT_is_symmetry_iteration_valid(i, symm)) { continue; } - cache->mirror_symmetry_pass = i; + const ePaintSymmetryFlags symm = ePaintSymmetryFlags(i); + cache->mirror_symmetry_pass = symm; cache->radial_symmetry_pass = 0; - SCULPT_cache_calc_brushdata_symm(cache, i, 0, 0); + SCULPT_cache_calc_brushdata_symm(cache, symm, 0, 0); do_tiled(sd, ob, brush, ups, paint_mode_settings, action); - do_radial_symmetry(sd, ob, brush, ups, paint_mode_settings, action, i, 'X', feather); - do_radial_symmetry(sd, ob, brush, ups, paint_mode_settings, action, i, 'Y', feather); - do_radial_symmetry(sd, ob, brush, ups, paint_mode_settings, action, i, 'Z', feather); + do_radial_symmetry(sd, ob, brush, ups, paint_mode_settings, action, symm, 'X', feather); + do_radial_symmetry(sd, ob, brush, ups, paint_mode_settings, action, symm, 'Y', feather); + do_radial_symmetry(sd, ob, brush, ups, paint_mode_settings, action, symm, 'Z', feather); } } @@ -4167,11 +4164,9 @@ void SCULPT_cache_free(StrokeCache *cache) /* Initialize mirror modifier clipping. */ static void sculpt_init_mirror_clipping(Object *ob, SculptSession *ss) { - ModifierData *md; - unit_m4(ss->cache->clip_mirror_mtx); - for (md = ob->modifiers.first; md; md = md->next) { + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { if (!(md->type == eModifierType_Mirror && (md->mode & eModifierMode_Realtime))) { continue; } @@ -4267,11 +4262,12 @@ static void smooth_brush_toggle_off(const bContext *C, Paint *paint, StrokeCache static void sculpt_update_cache_invariants( bContext *C, Sculpt *sd, SculptSession *ss, wmOperator *op, const float mval[2]) { - StrokeCache *cache = MEM_callocN(sizeof(StrokeCache), "stroke cache"); + StrokeCache *cache = static_cast<StrokeCache *>( + MEM_callocN(sizeof(StrokeCache), "stroke cache")); ToolSettings *tool_settings = CTX_data_tool_settings(C); UnifiedPaintSettings *ups = &tool_settings->unified_paint_settings; Brush *brush = BKE_paint_brush(&sd->paint); - ViewContext *vc = paint_stroke_view_context(op->customdata); + ViewContext *vc = paint_stroke_view_context(static_cast<PaintStroke *>(op->customdata)); Object *ob = CTX_data_active_object(C); float mat[3][3]; float viewDir[3] = {0.0f, 0.0f, 1.0f}; @@ -4825,8 +4821,8 @@ static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float *tmin) if (BKE_pbvh_node_get_tmin(node) >= *tmin) { return; } - SculptRaycastData *srd = data_v; - float(*origco)[3] = NULL; + SculptRaycastData *srd = static_cast<SculptRaycastData *>(data_v); + float(*origco)[3] = nullptr; bool use_origco = false; if (srd->original && srd->ss->cache) { @@ -4836,7 +4832,7 @@ static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float *tmin) else { /* Intersect with coordinates from before we started stroke. */ SculptUndoNode *unode = SCULPT_undo_get_node(node, SCULPT_UNDO_COORDS); - origco = (unode) ? unode->co : NULL; + origco = (unode) ? unode->co : nullptr; use_origco = origco ? true : false; } } @@ -4862,8 +4858,8 @@ static void sculpt_find_nearest_to_ray_cb(PBVHNode *node, void *data_v, float *t if (BKE_pbvh_node_get_tmin(node) >= *tmin) { return; } - SculptFindNearestToRayData *srd = data_v; - float(*origco)[3] = NULL; + SculptFindNearestToRayData *srd = static_cast<SculptFindNearestToRayData *>(data_v); + float(*origco)[3] = nullptr; bool use_origco = false; if (srd->original && srd->ss->cache) { @@ -4873,7 +4869,7 @@ static void sculpt_find_nearest_to_ray_cb(PBVHNode *node, void *data_v, float *t else { /* Intersect with coordinates from before we started stroke. */ SculptUndoNode *unode = SCULPT_undo_get_node(node, SCULPT_UNDO_COORDS); - origco = (unode) ? unode->co : NULL; + origco = (unode) ? unode->co : nullptr; use_origco = origco ? true : false; } } @@ -4901,7 +4897,7 @@ float SCULPT_raycast_init(ViewContext *vc, float obimat[4][4]; float dist; Object *ob = vc->obact; - RegionView3D *rv3d = vc->region->regiondata; + RegionView3D *rv3d = static_cast<RegionView3D *>(vc->region->regiondata); View3D *v3d = vc->v3d; /* TODO: what if the segment is totally clipped? (return == 0). */ @@ -4962,15 +4958,15 @@ bool SCULPT_cursor_geometry_info_update(bContext *C, depth = SCULPT_raycast_init(&vc, mval, ray_start, ray_end, ray_normal, original); SCULPT_stroke_modifiers_check(C, ob, brush); - SculptRaycastData srd = { - .original = original, - .ss = ob->sculpt, - .hit = false, - .ray_start = ray_start, - .ray_normal = ray_normal, - .depth = depth, - .face_normal = face_normal, - }; + SculptRaycastData srd{}; + srd.original = original; + srd.ss = ob->sculpt; + srd.hit = false; + srd.ray_start = ray_start; + srd.ray_normal = ray_normal; + srd.depth = depth; + srd.face_normal = face_normal; + isect_ray_tri_watertight_v3_precalc(&srd.isect_precalc, ray_normal); BKE_pbvh_raycast(ss->pbvh, sculpt_raycast_cb, &srd, ray_start, ray_normal, srd.original); @@ -5118,15 +5114,15 @@ bool SCULPT_stroke_get_location(bContext *C, return hit; } - SculptFindNearestToRayData srd = { - .original = original, - .ss = ob->sculpt, - .hit = false, - .ray_start = ray_start, - .ray_normal = ray_normal, - .depth = FLT_MAX, - .dist_sq_to_ray = FLT_MAX, - }; + SculptFindNearestToRayData srd{}; + srd.original = original; + srd.ss = ob->sculpt; + srd.hit = false; + srd.ray_start = ray_start; + srd.ray_normal = ray_normal; + srd.depth = FLT_MAX; + srd.dist_sq_to_ray = FLT_MAX; + BKE_pbvh_find_nearest_to_ray( ss->pbvh, sculpt_find_nearest_to_ray_cb, &srd, ray_start, ray_normal, srd.original); if (srd.hit) { @@ -5150,7 +5146,7 @@ static void sculpt_brush_init_tex(Sculpt *sd, SculptSession *ss) ntreeTexBeginExecTree(mtex->tex->nodetree); } - if (ss->tex_pool == NULL) { + if (ss->tex_pool == nullptr) { ss->tex_pool = BKE_image_pool_new(); } } @@ -5251,7 +5247,7 @@ void SCULPT_flush_update_step(bContext *C, SculptUpdateType update_flags) rv3d->rflag |= RV3D_PAINTING; } - if (mmd != NULL) { + if (mmd != nullptr) { multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED); } @@ -5312,7 +5308,7 @@ void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType up wmWindowManager *wm = CTX_wm_manager(C); RegionView3D *current_rv3d = CTX_wm_region_view3d(C); SculptSession *ss = ob->sculpt; - Mesh *mesh = ob->data; + Mesh *mesh = static_cast<Mesh *>(ob->data); /* Always needed for linked duplicates. */ bool need_tag = (ID_REAL_USERS(&mesh->id) > 1); @@ -5324,7 +5320,7 @@ void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType up LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { bScreen *screen = WM_window_get_active_screen(win); LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { - SpaceLink *sl = area->spacedata.first; + SpaceLink *sl = static_cast<SpaceLink *>(area->spacedata.first); if (sl->spacetype != SPACE_VIEW3D) { continue; } @@ -5334,7 +5330,7 @@ void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType up * current viewport was deactivated. */ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { if (region->regiontype == RGN_TYPE_WINDOW) { - RegionView3D *rv3d = region->regiondata; + RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata); if (rv3d != current_rv3d) { need_tag |= !BKE_sculptsession_use_pbvh_draw(ob, rv3d); } @@ -5346,7 +5342,7 @@ void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType up if (update_flags & SCULPT_UPDATE_IMAGE) { LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { - SpaceLink *sl = area->spacedata.first; + SpaceLink *sl = static_cast<SpaceLink *>(area->spacedata.first); if (sl->spacetype != SPACE_IMAGE) { continue; } @@ -5392,7 +5388,7 @@ void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType up /* Returns whether the mouse/stylus is over the mesh (1) * or over the background (0). */ -static bool over_mesh(bContext *C, struct wmOperator *UNUSED(op), const float mval[2]) +static bool over_mesh(bContext *C, wmOperator * /*op*/, const float mval[2]) { float co_dummy[3]; return SCULPT_stroke_get_location(C, co_dummy, mval, false); @@ -5448,13 +5444,13 @@ bool SCULPT_handles_colors_report(SculptSession *ss, ReportList *reports) return false; } -static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const float mval[2]) +static bool sculpt_stroke_test_start(bContext *C, wmOperator *op, const float mval[2]) { /* Don't start the stroke until `mval` goes over the mesh. * NOTE: `mval` will only be null when re-executing the saved stroke. * We have exception for 'exec' strokes since they may not set `mval`, * only 'location', see: T52195. */ - if (((op->flag & OP_IS_INVOKE) == 0) || (mval == NULL) || over_mesh(C, op, mval)) { + if (((op->flag & OP_IS_INVOKE) == 0) || (mval == nullptr) || over_mesh(C, op, mval)) { Object *ob = CTX_data_active_object(C); SculptSession *ss = ob->sculpt; Sculpt *sd = CTX_data_tool_settings(C)->sculpt; @@ -5489,8 +5485,8 @@ static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const f } static void sculpt_stroke_update_step(bContext *C, - wmOperator *UNUSED(op), - struct PaintStroke *stroke, + wmOperator * /*op*/, + PaintStroke *stroke, PointerRNA *itemptr) { UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings; @@ -5577,7 +5573,7 @@ static void sculpt_brush_exit_tex(Sculpt *sd) } } -static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(stroke)) +static void sculpt_stroke_done(const bContext *C, PaintStroke * /*stroke*/) { Object *ob = CTX_data_active_object(C); SculptSession *ss = ob->sculpt; @@ -5609,7 +5605,7 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str BKE_pbvh_node_color_buffer_free(ss->pbvh); SCULPT_cache_free(ss->cache); - ss->cache = NULL; + ss->cache = nullptr; sculpt_stroke_undo_end(C, brush); @@ -5635,7 +5631,7 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - struct PaintStroke *stroke; + PaintStroke *stroke; int ignore_background_click; int retval; Object *ob = CTX_data_active_object(C); @@ -5677,7 +5673,7 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent SCULPT_stroke_get_location, sculpt_stroke_test_start, sculpt_stroke_update_step, - NULL, + nullptr, sculpt_stroke_done, event->type); @@ -5685,15 +5681,15 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent /* For tablet rotation. */ ignore_background_click = RNA_boolean_get(op->ptr, "ignore_background_click"); - - if (ignore_background_click && !over_mesh(C, op, (const float[2]){UNPACK2(event->mval)})) { - paint_stroke_free(C, op, op->customdata); + const float mval[2] = {float(event->mval[0]), float(event->mval[1])}; + if (ignore_background_click && !over_mesh(C, op, mval)) { + paint_stroke_free(C, op, static_cast<PaintStroke *>(op->customdata)); return OPERATOR_PASS_THROUGH; } retval = op->type->modal(C, op, event); if (ELEM(retval, OPERATOR_FINISHED, OPERATOR_CANCELLED)) { - paint_stroke_free(C, op, op->customdata); + paint_stroke_free(C, op, static_cast<PaintStroke *>(op->customdata)); return retval; } /* Add modal handler. */ @@ -5714,12 +5710,12 @@ static int sculpt_brush_stroke_exec(bContext *C, wmOperator *op) SCULPT_stroke_get_location, sculpt_stroke_test_start, sculpt_stroke_update_step, - NULL, + nullptr, sculpt_stroke_done, 0); /* Frees op->customdata. */ - paint_stroke_exec(C, op, op->customdata); + paint_stroke_exec(C, op, static_cast<PaintStroke *>(op->customdata)); return OPERATOR_FINISHED; } @@ -5737,11 +5733,11 @@ static void sculpt_brush_stroke_cancel(bContext *C, wmOperator *op) paint_mesh_restore_co(sd, ob); } - paint_stroke_cancel(C, op, op->customdata); + paint_stroke_cancel(C, op, static_cast<PaintStroke *>(op->customdata)); if (ss->cache) { SCULPT_cache_free(ss->cache); - ss->cache = NULL; + ss->cache = nullptr; } sculpt_brush_exit_tex(sd); @@ -5749,9 +5745,9 @@ static void sculpt_brush_stroke_cancel(bContext *C, wmOperator *op) static int sculpt_brush_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event) { - bool started = op->customdata && paint_stroke_started((struct PaintStroke *)op->customdata); + bool started = op->customdata && paint_stroke_started((PaintStroke *)op->customdata); - int retval = paint_stroke_modal(C, op, event, (struct PaintStroke **)&op->customdata); + int retval = paint_stroke_modal(C, op, event, (PaintStroke **)&op->customdata); if (!started && ELEM(retval, OPERATOR_FINISHED, OPERATOR_CANCELLED)) { /* Did the stroke never start? If so push a blank sculpt undo @@ -5774,7 +5770,7 @@ static int sculpt_brush_stroke_modal(bContext *C, wmOperator *op, const wmEvent return retval; } -static void sculpt_redo_empty_ui(bContext *UNUSED(C), wmOperator *UNUSED(op)) +static void sculpt_redo_empty_ui(bContext * /*C*/, wmOperator * /*op*/) { } @@ -5845,8 +5841,8 @@ static int SCULPT_vertex_get_connected_component(SculptSession *ss, PBVHVertRef static void SCULPT_fake_neighbor_init(SculptSession *ss, const float max_dist) { const int totvert = SCULPT_vertex_count_get(ss); - ss->fake_neighbors.fake_neighbor_index = MEM_malloc_arrayN( - totvert, sizeof(int), "fake neighbor"); + ss->fake_neighbors.fake_neighbor_index = static_cast<int *>( + MEM_malloc_arrayN(totvert, sizeof(int), "fake neighbor")); for (int i = 0; i < totvert; i++) { ss->fake_neighbors.fake_neighbor_index[i] = FAKE_NEIGHBOR_NONE; } @@ -5870,19 +5866,20 @@ static void sculpt_pose_fake_neighbors_free(SculptSession *ss) MEM_SAFE_FREE(ss->fake_neighbors.fake_neighbor_index); } -typedef struct NearestVertexFakeNeighborTLSData { +struct NearestVertexFakeNeighborTLSData { PBVHVertRef nearest_vertex; float nearest_vertex_distance_squared; int current_topology_id; -} NearestVertexFakeNeighborTLSData; +}; static void do_fake_neighbor_search_task_cb(void *__restrict userdata, const int n, const TaskParallelTLS *__restrict tls) { - SculptThreadedTaskData *data = userdata; + SculptThreadedTaskData *data = static_cast<SculptThreadedTaskData *>(userdata); SculptSession *ss = data->ob->sculpt; - NearestVertexFakeNeighborTLSData *nvtd = tls->userdata_chunk; + NearestVertexFakeNeighborTLSData *nvtd = static_cast<NearestVertexFakeNeighborTLSData *>( + tls->userdata_chunk); PBVHVertexIter vd; BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -5900,12 +5897,13 @@ static void do_fake_neighbor_search_task_cb(void *__restrict userdata, BKE_pbvh_vertex_iter_end; } -static void fake_neighbor_search_reduce(const void *__restrict UNUSED(userdata), +static void fake_neighbor_search_reduce(const void *__restrict /*userdata*/, void *__restrict chunk_join, void *__restrict chunk) { - NearestVertexFakeNeighborTLSData *join = chunk_join; - NearestVertexFakeNeighborTLSData *nvtd = chunk; + NearestVertexFakeNeighborTLSData *join = static_cast<NearestVertexFakeNeighborTLSData *>( + chunk_join); + NearestVertexFakeNeighborTLSData *nvtd = static_cast<NearestVertexFakeNeighborTLSData *>(chunk); if (join->nearest_vertex.i == PBVH_REF_NONE) { join->nearest_vertex = nvtd->nearest_vertex; join->nearest_vertex_distance_squared = nvtd->nearest_vertex_distance_squared; @@ -5922,27 +5920,26 @@ static PBVHVertRef SCULPT_fake_neighbor_search(Sculpt *sd, float max_distance) { SculptSession *ss = ob->sculpt; - PBVHNode **nodes = NULL; + PBVHNode **nodes = nullptr; int totnode; - SculptSearchSphereData data = { - .ss = ss, - .sd = sd, - .radius_squared = max_distance * max_distance, - .original = false, - .center = SCULPT_vertex_co_get(ss, vertex), - }; + SculptSearchSphereData data{}; + data.ss = ss; + data.sd = sd; + data.radius_squared = max_distance * max_distance; + data.original = false; + data.center = SCULPT_vertex_co_get(ss, vertex); + BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, &totnode); if (totnode == 0) { return BKE_pbvh_make_vref(PBVH_REF_NONE); } - SculptThreadedTaskData task_data = { - .sd = sd, - .ob = ob, - .nodes = nodes, - .max_distance_squared = max_distance * max_distance, - }; + SculptThreadedTaskData task_data{}; + task_data.sd = sd; + task_data.ob = ob; + task_data.nodes = nodes; + task_data.max_distance_squared = max_distance * max_distance; copy_v3_v3(task_data.nearest_vertex_search_co, SCULPT_vertex_co_get(ss, vertex)); @@ -5963,17 +5960,14 @@ static PBVHVertRef SCULPT_fake_neighbor_search(Sculpt *sd, return nvtd.nearest_vertex; } -typedef struct SculptTopologyIDFloodFillData { +struct SculptTopologyIDFloodFillData { int next_id; -} SculptTopologyIDFloodFillData; +}; -static bool SCULPT_connected_components_floodfill_cb(SculptSession *ss, - PBVHVertRef from_v, - PBVHVertRef to_v, - bool UNUSED(is_duplicate), - void *userdata) +static bool SCULPT_connected_components_floodfill_cb( + SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool /*is_duplicate*/, void *userdata) { - SculptTopologyIDFloodFillData *data = userdata; + SculptTopologyIDFloodFillData *data = static_cast<SculptTopologyIDFloodFillData *>(userdata); int from_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, from_v); int to_v_i = BKE_pbvh_vertex_to_index(ss->pbvh, to_v); @@ -5995,7 +5989,8 @@ void SCULPT_connected_components_ensure(Object *ob) } const int totvert = SCULPT_vertex_count_get(ss); - ss->vertex_info.connected_component = MEM_malloc_arrayN(totvert, sizeof(int), "topology ID"); + ss->vertex_info.connected_component = static_cast<int *>( + MEM_malloc_arrayN(totvert, sizeof(int), "topology ID")); for (int i = 0; i < totvert; i++) { ss->vertex_info.connected_component[i] = SCULPT_TOPOLOGY_ID_NONE; @@ -6031,8 +6026,8 @@ void SCULPT_boundary_info_ensure(Object *object) const MLoop *loops = BKE_mesh_loops(base_mesh); ss->vertex_info.boundary = BLI_BITMAP_NEW(base_mesh->totvert, "Boundary info"); - int *adjacent_faces_edge_count = MEM_calloc_arrayN( - base_mesh->totedge, sizeof(int), "Adjacent face edge count"); + int *adjacent_faces_edge_count = static_cast<int *>( + MEM_calloc_arrayN(base_mesh->totedge, sizeof(int), "Adjacent face edge count")); for (int p = 0; p < base_mesh->totpoly; p++) { const MPoly *poly = &polys[p]; @@ -6086,14 +6081,14 @@ void SCULPT_fake_neighbors_ensure(Sculpt *sd, Object *ob, const float max_dist) void SCULPT_fake_neighbors_enable(Object *ob) { SculptSession *ss = ob->sculpt; - BLI_assert(ss->fake_neighbors.fake_neighbor_index != NULL); + BLI_assert(ss->fake_neighbors.fake_neighbor_index != nullptr); ss->fake_neighbors.use_fake_neighbors = true; } void SCULPT_fake_neighbors_disable(Object *ob) { SculptSession *ss = ob->sculpt; - BLI_assert(ss->fake_neighbors.fake_neighbor_index != NULL); + BLI_assert(ss->fake_neighbors.fake_neighbor_index != nullptr); ss->fake_neighbors.use_fake_neighbors = false; } @@ -6104,7 +6099,7 @@ void SCULPT_fake_neighbors_free(Object *ob) } void SCULPT_automasking_node_begin(Object *ob, - const SculptSession *UNUSED(ss), + const SculptSession * /*ss*/, AutomaskingCache *automasking, AutomaskingNodeData *automask_data, PBVHNode *node) @@ -6126,7 +6121,7 @@ void SCULPT_automasking_node_begin(Object *ob, } } -void SCULPT_automasking_node_update(SculptSession *UNUSED(ss), +void SCULPT_automasking_node_update(SculptSession * /*ss*/, AutomaskingNodeData *automask_data, PBVHVertexIter *vd) { @@ -6172,7 +6167,7 @@ void SCULPT_stroke_id_next(Object *ob) /* Manually wrap in int32 space to avoid tripping up undefined behavior * sanitizers. */ - ob->sculpt->stroke_id = (uchar)(((int)ob->sculpt->stroke_id + 1) & 255); + ob->sculpt->stroke_id = uchar((int(ob->sculpt->stroke_id) + 1) & 255); } void SCULPT_stroke_id_ensure(Object *ob) diff --git a/source/blender/editors/sculpt_paint/sculpt_brush_types.c b/source/blender/editors/sculpt_paint/sculpt_brush_types.c index 37dfd03c6f7..c24bdba662a 100644 --- a/source/blender/editors/sculpt_paint/sculpt_brush_types.c +++ b/source/blender/editors/sculpt_paint/sculpt_brush_types.c @@ -1441,6 +1441,9 @@ static void do_rotate_brush_task_cb_ex(void *__restrict userdata, if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { continue; } + + SCULPT_automasking_node_update(ss, &automask_data, &vd); + float vec[3], rot[3][3]; const float fade = bstrength * SCULPT_brush_strength_factor(ss, brush, diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 0fa43d08313..a06d6348a7d 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -341,7 +341,7 @@ typedef struct SculptBrushTest { float radius; float location[3]; float dist; - int mirror_symmetry_pass; + ePaintSymmetryFlags mirror_symmetry_pass; int radial_symmetry_pass; float symm_rot_mat_inv[4][4]; @@ -556,7 +556,8 @@ typedef struct StrokeCache { /* Symmetry index between 0 and 7 bit combo 0 is Brush only; * 1 is X mirror; 2 is Y mirror; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */ int symmetry; - int mirror_symmetry_pass; /* The symmetry pass we are currently on between 0 and 7. */ + ePaintSymmetryFlags + mirror_symmetry_pass; /* The symmetry pass we are currently on between 0 and 7. */ float true_view_normal[3]; float view_normal[3]; @@ -1526,7 +1527,10 @@ bool SCULPT_pbvh_calc_area_normal(const struct Brush *brush, * Flip all the edit-data across the axis/axes specified by \a symm. * Used to calculate multiple modifications to the mesh when symmetry is enabled. */ -void SCULPT_cache_calc_brushdata_symm(StrokeCache *cache, char symm, char axis, float angle); +void SCULPT_cache_calc_brushdata_symm(StrokeCache *cache, + ePaintSymmetryFlags symm, + char axis, + float angle); void SCULPT_cache_free(StrokeCache *cache); /* -------------------------------------------------------------------- */ diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.c b/source/blender/editors/sculpt_paint/sculpt_ops.c index 8affb0e9d53..0e7873bc652 100644 --- a/source/blender/editors/sculpt_paint/sculpt_ops.c +++ b/source/blender/editors/sculpt_paint/sculpt_ops.c @@ -246,15 +246,17 @@ static void SCULPT_OT_symmetrize(wmOperatorType *ot) ot->exec = sculpt_symmetrize_exec; ot->poll = sculpt_no_multires_poll; - RNA_def_float(ot->srna, - "merge_tolerance", - 0.001f, - 0.0f, - FLT_MAX, - "Merge Distance", - "Distance within which symmetrical vertices are merged", - 0.0f, - 1.0f); + PropertyRNA *prop = RNA_def_float(ot->srna, + "merge_tolerance", + 0.0005f, + 0.0f, + FLT_MAX, + "Merge Distance", + "Distance within which symmetrical vertices are merged", + 0.0f, + 1.0f); + + RNA_def_property_ui_range(prop, 0.0, FLT_MAX, 0.001, 5); } /**** Toggle operator for turning sculpt mode on or off ****/ @@ -1202,7 +1204,7 @@ static void SCULPT_OT_mask_from_cavity(wmOperatorType *ot) RNA_def_boolean(ot->srna, "use_automask_settings", false, - "Use Automask Settings", + "Automask Settings", "Use default settings from Options panel in sculpt mode"); RNA_def_float(ot->srna, @@ -1210,7 +1212,7 @@ static void SCULPT_OT_mask_from_cavity(wmOperatorType *ot) 0.5f, 0.0f, 5.0f, - "Cavity Factor", + "Factor", "The contrast of the cavity mask", 0.0f, 1.0f); @@ -1219,11 +1221,11 @@ static void SCULPT_OT_mask_from_cavity(wmOperatorType *ot) 2, 0, 25, - "Cavity Blur", + "Blur", "The number of times the cavity mask is blurred", 0, 25); - RNA_def_boolean(ot->srna, "use_curve", false, "Use Curve", ""); + RNA_def_boolean(ot->srna, "use_curve", false, "Custom Curve", ""); RNA_def_boolean(ot->srna, "invert", false, "Cavity (Inverted)", ""); } diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index f5c074d2105..de0935a0e22 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -1819,9 +1819,7 @@ static void sculpt_undo_set_active_layer(struct bContext *C, SculptAttrRef *attr if (!layer) { layer = BKE_id_attribute_search(&me->id, attr->name, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL); if (layer) { - const eAttrDomain domain = BKE_id_attribute_domain(&me->id, layer); - if (ED_geometry_attribute_convert( - me, attr->name, layer->type, domain, attr->type, attr->domain)) { + if (ED_geometry_attribute_convert(me, attr->name, attr->type, attr->domain, NULL)) { layer = BKE_id_attribute_find(&me->id, attr->name, attr->type, attr->domain); } } diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c index 9a690f36aab..10a037a1c3c 100644 --- a/source/blender/editors/space_clip/clip_editor.c +++ b/source/blender/editors/space_clip/clip_editor.c @@ -676,8 +676,8 @@ typedef struct PrefetchQueue { SpinLock spin; - short *stop; - short *do_update; + bool *stop; + bool *do_update; float *progress; } PrefetchQueue; @@ -819,7 +819,7 @@ static uchar *prefetch_thread_next_frame(PrefetchQueue *queue, (queue->initial_frame - queue->current_frame); } - *queue->do_update = 1; + *queue->do_update = true; *queue->progress = (float)frames_processed / (queue->end_frame - queue->start_frame); } } @@ -868,7 +868,7 @@ static void prefetch_task_func(TaskPool *__restrict pool, void *task_data) if (!result) { /* no more space in the cache, stop reading frames */ - *queue->stop = 1; + *queue->stop = true; break; } } @@ -880,8 +880,8 @@ static void start_prefetch_threads(MovieClip *clip, int end_frame, short render_size, short render_flag, - short *stop, - short *do_update, + bool *stop, + bool *do_update, float *progress) { int tot_thread = BLI_task_scheduler_num_threads(); @@ -918,7 +918,7 @@ static bool prefetch_movie_frame(MovieClip *clip, int frame, short render_size, short render_flag, - short *stop) + bool *stop) { MovieClipUser user = *DNA_struct_default_get(MovieClipUser); @@ -940,14 +940,14 @@ static bool prefetch_movie_frame(MovieClip *clip, if (!result) { /* no more space in the cache, we could stop prefetching here */ - *stop = 1; + *stop = true; } IMB_freeImBuf(ibuf); } else { /* error reading frame, fair enough stop attempting further reading */ - *stop = 1; + *stop = true; } } @@ -961,8 +961,8 @@ static void do_prefetch_movie(MovieClip *clip, int end_frame, short render_size, short render_flag, - short *stop, - short *do_update, + bool *stop, + bool *do_update, float *progress) { int frame; @@ -976,7 +976,7 @@ static void do_prefetch_movie(MovieClip *clip, frames_processed++; - *do_update = 1; + *do_update = true; *progress = (float)frames_processed / (end_frame - start_frame); } @@ -988,12 +988,12 @@ static void do_prefetch_movie(MovieClip *clip, frames_processed++; - *do_update = 1; + *do_update = true; *progress = (float)frames_processed / (end_frame - start_frame); } } -static void prefetch_startjob(void *pjv, short *stop, short *do_update, float *progress) +static void prefetch_startjob(void *pjv, bool *stop, bool *do_update, float *progress) { PrefetchJob *pj = pjv; diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c index 486f9f9ccb0..2c0668625a0 100644 --- a/source/blender/editors/space_clip/clip_ops.c +++ b/source/blender/editors/space_clip/clip_ops.c @@ -1219,8 +1219,8 @@ static void do_movie_proxy(void *pjv, int UNUSED(build_count), int *build_undistort_sizes, int build_undistort_count, - short *stop, - short *do_update, + bool *stop, + bool *do_update, float *progress) { ProxyJob *pj = pjv; @@ -1285,8 +1285,8 @@ typedef struct ProxyQueue { int efra; SpinLock spin; - const short *stop; - short *do_update; + const bool *stop; + bool *do_update; float *progress; } ProxyQueue; @@ -1343,7 +1343,7 @@ static uchar *proxy_thread_next_frame(ProxyQueue *queue, queue->cfra++; close(file); - *queue->do_update = 1; + *queue->do_update = true; *queue->progress = (float)(queue->cfra - queue->sfra) / (queue->efra - queue->sfra); } BLI_spin_unlock(&queue->spin); @@ -1392,8 +1392,8 @@ static void do_sequence_proxy(void *pjv, int build_undistort_count, /* Cannot be const, because it is assigned to a non-const variable. * NOLINTNEXTLINE: readability-non-const-parameter. */ - short *stop, - short *do_update, + bool *stop, + bool *do_update, float *progress) { ProxyJob *pj = pjv; @@ -1452,7 +1452,7 @@ static void do_sequence_proxy(void *pjv, MEM_freeN(handles); } -static void proxy_startjob(void *pjv, short *stop, short *do_update, float *progress) +static void proxy_startjob(void *pjv, bool *stop, bool *do_update, float *progress) { ProxyJob *pj = pjv; MovieClip *clip = pj->clip; diff --git a/source/blender/editors/space_clip/tracking_ops_solve.c b/source/blender/editors/space_clip/tracking_ops_solve.c index bfa45053e96..ddfcaa282e3 100644 --- a/source/blender/editors/space_clip/tracking_ops_solve.c +++ b/source/blender/editors/space_clip/tracking_ops_solve.c @@ -87,7 +87,7 @@ static void solve_camera_updatejob(void *scv) BLI_strncpy(tracking->stats->message, scj->stats_message, sizeof(tracking->stats->message)); } -static void solve_camera_startjob(void *scv, short *stop, short *do_update, float *progress) +static void solve_camera_startjob(void *scv, bool *stop, bool *do_update, float *progress) { SolveCameraJob *scj = (SolveCameraJob *)scv; BKE_tracking_reconstruction_solve( diff --git a/source/blender/editors/space_clip/tracking_ops_track.c b/source/blender/editors/space_clip/tracking_ops_track.c index f6fd2980c19..2753af609e7 100644 --- a/source/blender/editors/space_clip/tracking_ops_track.c +++ b/source/blender/editors/space_clip/tracking_ops_track.c @@ -204,8 +204,8 @@ static void track_markers_startjob( void *tmv, /* Cannot be const, this function implements wm_jobs_start_callback. * NOLINTNEXTLINE: readability-non-const-parameter. */ - short *stop, - short *do_update, + bool *stop, + bool *do_update, float *progress) { TrackMarkersJob *tmj = (TrackMarkersJob *)tmv; @@ -353,7 +353,7 @@ static int track_markers(bContext *C, wmOperator *op, bool use_job) return OPERATOR_RUNNING_MODAL; } - short stop = 0, do_update = 0; + bool stop = false, do_update = false; float progress = 0.0f; track_markers_startjob(tmj, &stop, &do_update, &progress); track_markers_endjob(tmj); diff --git a/source/blender/editors/space_file/CMakeLists.txt b/source/blender/editors/space_file/CMakeLists.txt index 688aa846c30..76564f38da8 100644 --- a/source/blender/editors/space_file/CMakeLists.txt +++ b/source/blender/editors/space_file/CMakeLists.txt @@ -46,6 +46,10 @@ set(LIB bf_blenkernel ) +if(WIN32) + add_definitions(-DNOMINMAX) +endif() + if(WITH_HEADLESS) add_definitions(-DWITH_HEADLESS) else() diff --git a/source/blender/editors/space_file/asset_catalog_tree_view.cc b/source/blender/editors/space_file/asset_catalog_tree_view.cc index 4eb2958f5a2..fe2e46fc056 100644 --- a/source/blender/editors/space_file/asset_catalog_tree_view.cc +++ b/source/blender/editors/space_file/asset_catalog_tree_view.cc @@ -708,12 +708,11 @@ bool file_set_asset_catalog_filter_settings( void file_ensure_updated_catalog_filter_data( FileAssetCatalogFilterSettingsHandle *filter_settings_handle, - const ::AssetLibrary *asset_library) + const bke::AssetLibrary *asset_library) { AssetCatalogFilterSettings *filter_settings = reinterpret_cast<AssetCatalogFilterSettings *>( filter_settings_handle); - const AssetCatalogService *catalog_service = BKE_asset_library_get_catalog_service( - asset_library); + const AssetCatalogService *catalog_service = asset_library->catalog_service.get(); if (filter_settings->asset_catalog_visibility != FILE_SHOW_ASSETS_ALL_CATALOGS) { filter_settings->catalog_filter = std::make_unique<AssetCatalogFilter>( diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index 240901318b5..ed0132c6990 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -171,7 +171,6 @@ static void file_draw_icon(const SpaceFile *sfile, UI_but_drag_set_asset(but, &(AssetHandle){.file_data = file}, BLI_strdup(blend_path), - file->asset_data, asset_params->import_type, icon, preview_image, @@ -565,7 +564,6 @@ static void file_draw_preview(const SpaceFile *sfile, UI_but_drag_set_asset(but, &(AssetHandle){.file_data = file}, BLI_strdup(blend_path), - file->asset_data, asset_params->import_type, icon, imb, diff --git a/source/blender/editors/space_file/file_indexer.cc b/source/blender/editors/space_file/file_indexer.cc index ec631eb48b3..8520ac34122 100644 --- a/source/blender/editors/space_file/file_indexer.cc +++ b/source/blender/editors/space_file/file_indexer.cc @@ -67,8 +67,9 @@ void ED_file_indexer_entries_extend_from_datablock_infos( } } -static void ED_file_indexer_entry_free(void *indexer_entry) +static void ED_file_indexer_entry_free(void *indexer_entry_ptr) { + FileIndexerEntry *indexer_entry = static_cast<FileIndexerEntry *>(indexer_entry_ptr); MEM_freeN(indexer_entry); } diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h index eac72af00ab..0ca09487507 100644 --- a/source/blender/editors/space_file/file_intern.h +++ b/source/blender/editors/space_file/file_intern.h @@ -218,6 +218,17 @@ void file_path_to_ui_path(const char *path, char *r_pathi, int max_size); /* C-handle for #ed::asset_browser::AssetCatalogFilterSettings. */ typedef struct FileAssetCatalogFilterSettingsHandle FileAssetCatalogFilterSettingsHandle; +void file_create_asset_catalog_tree_view_in_layout(struct AssetLibrary *asset_library, + struct uiLayout *layout, + SpaceFile *space_file, + FileAssetSelectParams *params); + +#ifdef __cplusplus + +namespace blender::bke { +struct AssetLibrary; +} + FileAssetCatalogFilterSettingsHandle *file_create_asset_catalog_filter_settings(void); void file_delete_asset_catalog_filter_settings( FileAssetCatalogFilterSettingsHandle **filter_settings_handle); @@ -231,15 +242,12 @@ bool file_set_asset_catalog_filter_settings( bUUID catalog_id); void file_ensure_updated_catalog_filter_data( FileAssetCatalogFilterSettingsHandle *filter_settings_handle, - const struct AssetLibrary *asset_library); + const blender::bke::AssetLibrary *asset_library); bool file_is_asset_visible_in_catalog_filter_settings( const FileAssetCatalogFilterSettingsHandle *filter_settings_handle, const AssetMetaData *asset_data); -void file_create_asset_catalog_tree_view_in_layout(struct AssetLibrary *asset_library, - struct uiLayout *layout, - struct SpaceFile *space_file, - struct FileAssetSelectParams *params); +#endif #ifdef __cplusplus } diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index f68d329329f..6d7365fa136 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -1309,6 +1309,18 @@ static int bookmark_move_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +static bool file_bookmark_move_poll(bContext *C) +{ + SpaceFile *sfile = CTX_wm_space_file(C); + + /* Bookmarks are for file browsing only (not asset browsing). */ + if (!ED_operator_file_browsing_active(C)) { + return false; + } + + return sfile->bookmarknr != -1; +} + void FILE_OT_bookmark_move(wmOperatorType *ot) { static const EnumPropertyItem slot_move[] = { @@ -1325,8 +1337,7 @@ void FILE_OT_bookmark_move(wmOperatorType *ot) /* api callbacks */ ot->exec = bookmark_move_exec; - /* Bookmarks are for file browsing only (not asset browsing). */ - ot->poll = ED_operator_file_browsing_active; + ot->poll = file_bookmark_move_poll; /* flags */ ot->flag = OPTYPE_REGISTER; /* No undo! */ diff --git a/source/blender/editors/space_file/filelist.cc b/source/blender/editors/space_file/filelist.cc index 3870178f119..c4d99d41a60 100644 --- a/source/blender/editors/space_file/filelist.cc +++ b/source/blender/editors/space_file/filelist.cc @@ -43,6 +43,8 @@ #include "BKE_asset.h" #include "BKE_asset_library.h" +#include "BKE_asset_library.hh" +#include "BKE_asset_representation.hh" #include "BKE_context.h" #include "BKE_global.h" #include "BKE_icons.h" @@ -78,6 +80,8 @@ #include "file_intern.h" #include "filelist.h" +using namespace blender; + #define FILEDIR_NBR_ENTRIES_UNSET -1 /* ------------------FILELIST------------------------ */ @@ -95,7 +99,7 @@ struct FileListInternEntry { /** Optional argument for shortcuts, aliases etc. */ char *redirection_path; /** not strictly needed, but used during sorting, avoids to have to recompute it there... */ - char *name; + const char *name; bool free_name; /** @@ -112,9 +116,8 @@ struct FileListInternEntry { PreviewImage *preview_image; } local_data; - /** When the file represents an asset read from another file, it is stored here. - * Owning pointer. */ - AssetMetaData *imported_asset_data; + /* References an asset in the asset library storage. */ + bke::AssetRepresentation *asset; /* Non-owning. */ /* See #FILE_ENTRY_BLENDERLIB_NO_PREVIEW. */ bool blenderlib_has_no_preview; @@ -210,7 +213,7 @@ struct FileList { eFileSelectType type; /* The library this list was created for. Stored here so we know when to re-read. */ AssetLibraryReference *asset_library_ref; - AssetLibrary *asset_library; /* Non-owning pointer. */ + bke::AssetLibrary *asset_library; /* Non-owning. */ short flags; @@ -246,7 +249,7 @@ struct FileList { bool (*check_dir_fn)(struct FileList *, char *, const bool); /* Fill filelist (to be called by read job). */ - void (*read_job_fn)(struct FileListReadJob *, short *, short *, float *); + void (*read_job_fn)(struct FileListReadJob *, bool *, bool *, float *); /* Filter an entry of current filelist. */ bool (*filter_fn)(struct FileListInternEntry *, const char *, FileListFilter *); @@ -295,24 +298,24 @@ enum { static ImBuf *gSpecialFileImages[SPECIAL_IMG_MAX]; static void filelist_readjob_main(FileListReadJob *job_params, - short *stop, - short *do_update, + bool *stop, + bool *do_update, float *progress); static void filelist_readjob_lib(FileListReadJob *job_params, - short *stop, - short *do_update, + bool *stop, + bool *do_update, float *progress); static void filelist_readjob_dir(FileListReadJob *job_params, - short *stop, - short *do_update, + bool *stop, + bool *do_update, float *progress); static void filelist_readjob_asset_library(FileListReadJob *job_params, - short *stop, - short *do_update, + bool *stop, + bool *do_update, float *progress); static void filelist_readjob_main_assets(FileListReadJob *job_params, - short *stop, - short *do_update, + bool *stop, + bool *do_update, float *progress); /* helper, could probably go in BKE actually? */ @@ -776,8 +779,10 @@ static bool is_filtered_id_file_type(const FileListInternEntry *file, */ static AssetMetaData *filelist_file_internal_get_asset_data(const FileListInternEntry *file) { - const ID *local_id = file->local_data.id; - return local_id ? local_id->asset_data : file->imported_asset_data; + if (!file->asset) { + return nullptr; + } + return &file->asset->get_metadata(); } static void prepare_filter_asset_library(const FileList *filelist, FileListFilter *filter) @@ -1016,7 +1021,7 @@ void filelist_setindexer(FileList *filelist, const FileIndexerType *indexer) void filelist_set_asset_catalog_filter_options( FileList *filelist, eFileSel_Params_AssetCatalogVisibility catalog_visibility, - const bUUID *catalog_id) + const ::bUUID *catalog_id) { if (!filelist->filter_data.asset_catalog_filter) { /* There's no filter data yet. */ @@ -1362,7 +1367,7 @@ static bool filelist_checkdir_main_assets(struct FileList * /*filelist*/, static void filelist_entry_clear(FileDirEntry *entry) { if (entry->name && ((entry->flags & FILE_ENTRY_NAME_FREE) != 0)) { - MEM_freeN(entry->name); + MEM_freeN((char *)entry->name); } if (entry->relpath) { MEM_freeN(entry->relpath); @@ -1399,8 +1404,13 @@ static void filelist_direntryarr_free(FileDirEntryArr *array) array->entries_filtered_num = FILEDIR_NBR_ENTRIES_UNSET; } -static void filelist_intern_entry_free(FileListInternEntry *entry) +static void filelist_intern_entry_free(FileList *filelist, FileListInternEntry *entry) { + if (entry->asset) { + BLI_assert(filelist->asset_library); + filelist->asset_library->remove_asset(*entry->asset); + } + if (entry->relpath) { MEM_freeN(entry->relpath); } @@ -1408,19 +1418,16 @@ static void filelist_intern_entry_free(FileListInternEntry *entry) MEM_freeN(entry->redirection_path); } if (entry->name && entry->free_name) { - MEM_freeN(entry->name); - } - /* If we own the asset-data (it was generated from external file data), free it. */ - if (entry->imported_asset_data) { - BKE_asset_metadata_free(&entry->imported_asset_data); + MEM_freeN((char *)entry->name); } MEM_freeN(entry); } -static void filelist_intern_free(FileListIntern *filelist_intern) +static void filelist_intern_free(FileList *filelist) { + FileListIntern *filelist_intern = &filelist->filelist_intern; LISTBASE_FOREACH_MUTABLE (FileListInternEntry *, entry, &filelist_intern->entries) { - filelist_intern_entry_free(entry); + filelist_intern_entry_free(filelist, entry); } BLI_listbase_clear(&filelist_intern->entries); @@ -1430,8 +1437,9 @@ static void filelist_intern_free(FileListIntern *filelist_intern) /** * \return the number of main files removed. */ -static int filelist_intern_free_main_files(FileListIntern *filelist_intern) +static int filelist_intern_free_main_files(FileList *filelist) { + FileListIntern *filelist_intern = &filelist->filelist_intern; int removed_counter = 0; LISTBASE_FOREACH_MUTABLE (FileListInternEntry *, entry, &filelist_intern->entries) { if (!filelist_intern_entry_is_main_file(entry)) { @@ -1439,7 +1447,7 @@ static int filelist_intern_free_main_files(FileListIntern *filelist_intern) } BLI_remlink(&filelist_intern->entries, entry); - filelist_intern_entry_free(entry); + filelist_intern_entry_free(filelist, entry); removed_counter++; } @@ -1794,7 +1802,7 @@ void filelist_clear_ex(struct FileList *filelist, filelist_cache_clear(&filelist->filelist_cache, filelist->filelist_cache.size); } - filelist_intern_free(&filelist->filelist_intern); + filelist_intern_free(filelist); filelist_direntryarr_free(&filelist->filelist); @@ -1822,7 +1830,7 @@ static void filelist_clear_main_files(FileList *filelist, filelist_cache_clear(&filelist->filelist_cache, filelist->filelist_cache.size); } - const int removed_files = filelist_intern_free_main_files(&filelist->filelist_intern); + const int removed_files = filelist_intern_free_main_files(filelist); filelist->filelist.entries_num -= removed_files; filelist->filelist.entries_filtered_num = FILEDIR_NBR_ENTRIES_UNSET; @@ -1881,7 +1889,7 @@ void filelist_free(struct FileList *filelist) AssetLibrary *filelist_asset_library(FileList *filelist) { - return filelist->asset_library; + return reinterpret_cast<::AssetLibrary *>(filelist->asset_library); } void filelist_freelib(struct FileList *filelist) @@ -1897,11 +1905,15 @@ BlendHandle *filelist_lib(struct FileList *filelist) return filelist->libfiledata; } -static char *fileentry_uiname(const char *root, - const char *relpath, - const eFileSel_File_Types typeflag, - char *buff) +static const char *fileentry_uiname(const char *root, FileListInternEntry *entry, char *buff) { + if (entry->asset) { + const StringRefNull asset_name = entry->asset->get_name(); + return BLI_strdupn(asset_name.c_str(), asset_name.size()); + } + + const char *relpath = entry->relpath; + const eFileSel_File_Types typeflag = entry->typeflag; char *name = nullptr; if (typeflag & FILE_TYPE_FTFONT && !(typeflag & FILE_TYPE_BLENDERLIB)) { @@ -2042,10 +2054,7 @@ static FileDirEntry *filelist_file_create_entry(FileList *filelist, const int in ret->redirection_path = BLI_strdup(entry->redirection_path); } ret->id = entry->local_data.id; - ret->asset_data = entry->imported_asset_data ? entry->imported_asset_data : nullptr; - if (ret->id && (ret->asset_data == nullptr)) { - ret->asset_data = ret->id->asset_data; - } + ret->asset = reinterpret_cast<::AssetRepresentation *>(entry->asset); /* For some file types the preview is already available. */ if (entry->local_data.preview_image && BKE_previewimg_is_finished(entry->local_data.preview_image, ICON_SIZE_PREVIEW)) { @@ -2996,8 +3005,13 @@ static FileListInternEntry *filelist_readjob_list_lib_group_create(const int idc return entry; } -static void filelist_readjob_list_lib_add_datablock(ListBase *entries, - const BLODataBlockInfo *datablock_info, +/** + * \warning: This "steals" the asset metadata from \a datablock_info. Not great design but fixing + * this requires redesigning things on the caller side for proper ownership management. + */ +static void filelist_readjob_list_lib_add_datablock(FileList *filelist, + ListBase *entries, + BLODataBlockInfo *datablock_info, const bool prefix_relpath_with_group_name, const int idcode, const char *group_name) @@ -3010,21 +3024,29 @@ static void filelist_readjob_list_lib_add_datablock(ListBase *entries, entry->relpath = BLI_strdup(datablock_info->name); } entry->typeflag |= FILE_TYPE_BLENDERLIB; - if (datablock_info) { entry->blenderlib_has_no_preview = datablock_info->no_preview_found; if (datablock_info->asset_data) { entry->typeflag |= FILE_TYPE_ASSET; - /* Moves ownership! */ - entry->imported_asset_data = datablock_info->asset_data; + + if (filelist->asset_library) { + /** XXX Moving out the asset metadata like this isn't great. */ + std::unique_ptr metadata = BKE_asset_metadata_move_to_unique_ptr( + datablock_info->asset_data); + BKE_asset_metadata_free(&datablock_info->asset_data); + + entry->asset = &filelist->asset_library->add_external_asset(datablock_info->name, + std::move(metadata)); + } } } entry->blentype = idcode; BLI_addtail(entries, entry); } -static void filelist_readjob_list_lib_add_datablocks(ListBase *entries, +static void filelist_readjob_list_lib_add_datablocks(FileList *filelist, + ListBase *entries, LinkNode *datablock_infos, const bool prefix_relpath_with_group_name, const int idcode, @@ -3033,19 +3055,21 @@ static void filelist_readjob_list_lib_add_datablocks(ListBase *entries, for (LinkNode *ln = datablock_infos; ln; ln = ln->next) { struct BLODataBlockInfo *datablock_info = static_cast<BLODataBlockInfo *>(ln->link); filelist_readjob_list_lib_add_datablock( - entries, datablock_info, prefix_relpath_with_group_name, idcode, group_name); + filelist, entries, datablock_info, prefix_relpath_with_group_name, idcode, group_name); } } static void filelist_readjob_list_lib_add_from_indexer_entries( + FileList *filelist, ListBase *entries, const FileIndexerEntries *indexer_entries, const bool prefix_relpath_with_group_name) { for (const LinkNode *ln = indexer_entries->entries; ln; ln = ln->next) { - const FileIndexerEntry *indexer_entry = (const FileIndexerEntry *)ln->link; + FileIndexerEntry *indexer_entry = static_cast<FileIndexerEntry *>(ln->link); const char *group_name = BKE_idtype_idcode_to_name(indexer_entry->idcode); - filelist_readjob_list_lib_add_datablock(entries, + filelist_readjob_list_lib_add_datablock(filelist, + entries, &indexer_entry->datablock_info, prefix_relpath_with_group_name, indexer_entry->idcode, @@ -3073,7 +3097,8 @@ typedef struct FileIndexer { void *user_data; } FileIndexer; -static int filelist_readjob_list_lib_populate_from_index(ListBase *entries, +static int filelist_readjob_list_lib_populate_from_index(FileList *filelist, + ListBase *entries, const ListLibOptions options, const int read_from_index, const FileIndexerEntries *indexer_entries) @@ -3085,11 +3110,12 @@ static int filelist_readjob_list_lib_populate_from_index(ListBase *entries, navigate_to_parent_len = 1; } - filelist_readjob_list_lib_add_from_indexer_entries(entries, indexer_entries, true); + filelist_readjob_list_lib_add_from_indexer_entries(filelist, entries, indexer_entries, true); return read_from_index + navigate_to_parent_len; } -static int filelist_readjob_list_lib(const char *root, +static int filelist_readjob_list_lib(FileList *filelist, + const char *root, ListBase *entries, const ListLibOptions options, FileIndexer *indexer_runtime) @@ -3128,7 +3154,7 @@ static int filelist_readjob_list_lib(const char *root, dir, &indexer_entries, &read_from_index, indexer_runtime->user_data); if (indexer_result == FILE_INDEXER_ENTRIES_LOADED) { int entries_read = filelist_readjob_list_lib_populate_from_index( - entries, options, read_from_index, &indexer_entries); + filelist, entries, options, read_from_index, &indexer_entries); ED_file_indexer_entries_clear(&indexer_entries); return entries_read; } @@ -3158,7 +3184,8 @@ static int filelist_readjob_list_lib(const char *root, const int idcode = groupname_to_code(group); LinkNode *datablock_infos = BLO_blendhandle_get_datablock_info( libfiledata, idcode, options & LIST_LIB_ASSETS_ONLY, &datablock_len); - filelist_readjob_list_lib_add_datablocks(entries, datablock_infos, false, idcode, group); + filelist_readjob_list_lib_add_datablocks( + filelist, entries, datablock_infos, false, idcode, group); BLI_linklist_freeN(datablock_infos); } else { @@ -3177,7 +3204,7 @@ static int filelist_readjob_list_lib(const char *root, LinkNode *group_datablock_infos = BLO_blendhandle_get_datablock_info( libfiledata, idcode, options & LIST_LIB_ASSETS_ONLY, &group_datablock_len); filelist_readjob_list_lib_add_datablocks( - entries, group_datablock_infos, true, idcode, group_name); + filelist, entries, group_datablock_infos, true, idcode, group_name); if (use_indexer) { ED_file_indexer_entries_extend_from_datablock_infos( &indexer_entries, group_datablock_infos, idcode); @@ -3401,7 +3428,7 @@ struct FileListReadJob { static void filelist_readjob_append_entries(FileListReadJob *job_params, ListBase *from_entries, int from_entries_num, - short *do_update) + bool *do_update) { BLI_assert(BLI_listbase_count(from_entries) == from_entries_num); if (from_entries_num <= 0) { @@ -3456,8 +3483,8 @@ static bool filelist_readjob_should_recurse_into_entry(const int max_recursion, static void filelist_readjob_recursive_dir_add_items(const bool do_lib, FileListReadJob *job_params, - const short *stop, - short *do_update, + const bool *stop, + bool *do_update, float *progress) { FileList *filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */ @@ -3529,7 +3556,7 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib, list_lib_options |= LIST_LIB_ASSETS_ONLY; } entries_num = filelist_readjob_list_lib( - subdir, &entries, list_lib_options, &indexer_runtime); + filelist, subdir, &entries, list_lib_options, &indexer_runtime); if (entries_num > 0) { is_lib = true; } @@ -3550,7 +3577,7 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib, MEM_freeN(entry->relpath); entry->relpath = BLI_strdup(dir + 2); /* + 2 to remove '//' * added by BLI_path_rel to rel_subdir. */ - entry->name = fileentry_uiname(root, entry->relpath, entry->typeflag, dir); + entry->name = fileentry_uiname(root, entry, dir); entry->free_name = true; if (filelist_readjob_should_recurse_into_entry( @@ -3594,8 +3621,8 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib, static void filelist_readjob_do(const bool do_lib, FileListReadJob *job_params, - const short *stop, - short *do_update, + const bool *stop, + bool *do_update, float *progress) { FileList *filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */ @@ -3611,39 +3638,25 @@ static void filelist_readjob_do(const bool do_lib, } static void filelist_readjob_dir(FileListReadJob *job_params, - short *stop, - short *do_update, + bool *stop, + bool *do_update, float *progress) { filelist_readjob_do(false, job_params, stop, do_update, progress); } static void filelist_readjob_lib(FileListReadJob *job_params, - short *stop, - short *do_update, + bool *stop, + bool *do_update, float *progress) { filelist_readjob_do(true, job_params, stop, do_update, progress); } -static void filelist_asset_library_path(const FileListReadJob *job_params, - char r_library_root_path[FILE_MAX]) -{ - if (job_params->filelist->type == FILE_MAIN_ASSET) { - /* For the "Current File" library (#FILE_MAIN_ASSET) we get the asset library root path based - * on main. */ - BKE_asset_library_find_suitable_root_path_from_main(job_params->current_main, - r_library_root_path); - } - else { - BLI_strncpy(r_library_root_path, job_params->tmp_filelist->filelist.root, FILE_MAX); - } -} - /** * Load asset library data, which currently means loading the asset catalogs for the library. */ -static void filelist_readjob_load_asset_library_data(FileListReadJob *job_params, short *do_update) +static void filelist_readjob_load_asset_library_data(FileListReadJob *job_params, bool *do_update) { FileList *tmp_filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */ @@ -3657,18 +3670,16 @@ static void filelist_readjob_load_asset_library_data(FileListReadJob *job_params return; } - char library_root_path[FILE_MAX]; - filelist_asset_library_path(job_params, library_root_path); - /* Load asset catalogs, into the temp filelist for thread-safety. * #filelist_readjob_endjob() will move it into the real filelist. */ - tmp_filelist->asset_library = BKE_asset_library_load(library_root_path); + tmp_filelist->asset_library = BKE_asset_library_load(job_params->current_main, + *job_params->filelist->asset_library_ref); *do_update = true; } static void filelist_readjob_main_assets_add_items(FileListReadJob *job_params, - short * /*stop*/, - short *do_update, + bool * /*stop*/, + bool *do_update, float * /*progress*/) { FileList *filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */ @@ -3699,6 +3710,9 @@ static void filelist_readjob_main_assets_add_items(FileListReadJob *job_params, entry->local_data.preview_image = BKE_asset_metadata_preview_get_from_id(id_iter->asset_data, id_iter); entry->local_data.id = id_iter; + if (filelist->asset_library) { + entry->asset = &filelist->asset_library->add_local_id_asset(*id_iter); + } entries_num++; BLI_addtail(&tmp_entries, entry); } @@ -3729,8 +3743,8 @@ static bool filelist_contains_main(const FileList *filelist, const Main *bmain) } static void filelist_readjob_asset_library(FileListReadJob *job_params, - short *stop, - short *do_update, + bool *stop, + bool *do_update, float *progress) { FileList *filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */ @@ -3753,8 +3767,8 @@ static void filelist_readjob_asset_library(FileListReadJob *job_params, } static void filelist_readjob_main(FileListReadJob *job_params, - short *stop, - short *do_update, + bool *stop, + bool *do_update, float *progress) { /* TODO! */ @@ -3762,8 +3776,8 @@ static void filelist_readjob_main(FileListReadJob *job_params, } static void filelist_readjob_main_assets(FileListReadJob *job_params, - short *stop, - short *do_update, + bool *stop, + bool *do_update, float *progress) { FileList *filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */ @@ -3791,7 +3805,7 @@ static bool filelist_readjob_is_partial_read(const FileListReadJob *read_job) * some current entries are kept and we just call the readjob to update the main files (see * #FileListReadJob.only_main_data). */ -static void filelist_readjob_startjob(void *flrjv, short *stop, short *do_update, float *progress) +static void filelist_readjob_startjob(void *flrjv, bool *stop, bool *do_update, float *progress) { FileListReadJob *flrj = static_cast<FileListReadJob *>(flrjv); @@ -3939,8 +3953,8 @@ void filelist_readjob_start(FileList *filelist, const int space_notifier, const const bool no_threads = (filelist->tags & FILELIST_TAGS_NO_THREADS) || flrj->only_main_data; if (no_threads) { - short dummy_stop = false; - short dummy_do_update = false; + bool dummy_stop = false; + bool dummy_do_update = false; float dummy_progress = 0.0f; /* Single threaded execution. Just directly call the callbacks. */ diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c index cea53908d4f..959f8b01ec8 100644 --- a/source/blender/editors/space_file/fsmenu.c +++ b/source/blender/editors/space_file/fsmenu.c @@ -1147,8 +1147,8 @@ static void fsmenu_bookmark_validate_job_startjob( void *fsmenuv, /* Cannot be const, this function implements wm_jobs_start_callback. * NOLINTNEXTLINE: readability-non-const-parameter. */ - short *stop, - short *do_update, + bool *stop, + bool *do_update, float *UNUSED(progress)) { FSMenu *fsmenu = fsmenuv; diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 74f1b8e838a..95b87f06d96 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -950,7 +950,7 @@ static int /*eContextResult*/ file_context(const bContext *C, for (int file_index = 0; file_index < num_files_filtered; file_index++) { if (filelist_entry_is_selected(sfile->files, file_index)) { FileDirEntry *entry = filelist_file(sfile->files, file_index); - if (entry->asset_data) { + if (entry->asset) { CTX_data_list_add(result, &screen->id, &RNA_FileSelectEntry, entry); } } diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index a23b33dde95..cb01b0d9dc8 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -2333,6 +2333,48 @@ static int graphkeys_snap_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +static bool graph_has_selected_control_points(struct bContext *C) +{ + bAnimContext ac; + ListBase anim_data = {NULL, NULL}; + + /* Get editor data. */ + if (ANIM_animdata_get_context(C, &ac) == 0) { + return OPERATOR_CANCELLED; + } + + /* Filter data. */ + const int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY | + ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); + ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + + /* Check if any of the visible and editable f-curves have at least one selected control point. */ + bool has_selected_control_points = false; + LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) { + const FCurve *fcu = ale->key_data; + if (BKE_fcurve_has_selected_control_points(fcu)) { + has_selected_control_points = true; + break; + } + } + + ANIM_animdata_freelist(&anim_data); + + return has_selected_control_points; +} + +static int graphkeys_selected_control_points_invoke(struct bContext *C, + struct wmOperator *op, + const struct wmEvent *event) +{ + if (!graph_has_selected_control_points(C)) { + BKE_report(op->reports, RPT_ERROR, "No control points are selected"); + return OPERATOR_CANCELLED; + } + + return WM_menu_invoke(C, op, event); +} + void GRAPH_OT_snap(wmOperatorType *ot) { /* Identifiers */ @@ -2341,7 +2383,7 @@ void GRAPH_OT_snap(wmOperatorType *ot) ot->description = "Snap selected keyframes to the chosen times/values"; /* API callbacks */ - ot->invoke = WM_menu_invoke; + ot->invoke = graphkeys_selected_control_points_invoke; ot->exec = graphkeys_snap_exec; ot->poll = graphop_editable_keyframes_poll; @@ -2418,7 +2460,7 @@ void GRAPH_OT_equalize_handles(wmOperatorType *ot) "Ensure selected keyframes' handles have equal length, optionally making them horizontal. " "Automatic, Automatic Clamped, or Vector handle types will be converted to Aligned"; /* API callbacks */ - ot->invoke = WM_menu_invoke; + ot->invoke = graphkeys_selected_control_points_invoke; ot->exec = graphkeys_equalize_handles_exec; ot->poll = graphop_editable_keyframes_poll; diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c index 932ed417f21..3265dcbf0d1 100644 --- a/source/blender/editors/space_graph/graph_select.c +++ b/source/blender/editors/space_graph/graph_select.c @@ -1061,6 +1061,12 @@ static int graph_circle_select_exec(bContext *C, wmOperator *op) /* Apply box_select action. */ const bool any_key_selection_changed = box_select_graphkeys( &ac, &rect_fl, BEZT_OK_REGION_CIRCLE, selectmode, incl_handles, &data); + if (any_key_selection_changed) { + /* If any key was selected at any time during this process, the entire-curve selection should + * be disabled. Otherwise, sliding over any keyless part of the curve will immediately cause + * the entire curve to be selected. */ + RNA_boolean_set(op->ptr, "use_curve_selection", false); + } const bool use_curve_selection = RNA_boolean_get(op->ptr, "use_curve_selection"); if (use_curve_selection && !any_key_selection_changed) { box_select_graphcurves(&ac, &rect_fl, BEZT_OK_REGION_CIRCLE, selectmode, incl_handles, &data); diff --git a/source/blender/editors/space_graph/graph_slider_ops.c b/source/blender/editors/space_graph/graph_slider_ops.c index f3d92911155..62aecf930d3 100644 --- a/source/blender/editors/space_graph/graph_slider_ops.c +++ b/source/blender/editors/space_graph/graph_slider_ops.c @@ -458,16 +458,13 @@ static bool decimate_poll_property(const bContext *UNUSED(C), const PropertyRNA *prop) { const char *prop_id = RNA_property_identifier(prop); + const int mode = RNA_enum_get(op->ptr, "mode"); - if (STRPREFIX(prop_id, "remove")) { - int mode = RNA_enum_get(op->ptr, "mode"); - - if (STREQ(prop_id, "factor") && mode != DECIM_RATIO) { - return false; - } - if (STREQ(prop_id, "remove_error_margin") && mode != DECIM_ERROR) { - return false; - } + if (STREQ(prop_id, "factor") && mode != DECIM_RATIO) { + return false; + } + if (STREQ(prop_id, "remove_error_margin") && mode != DECIM_ERROR) { + return false; } return true; diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c index 0122e509c3b..68b1a9e4466 100644 --- a/source/blender/editors/space_image/image_edit.c +++ b/source/blender/editors/space_image/image_edit.c @@ -67,6 +67,30 @@ void ED_space_image_set(Main *bmain, SpaceImage *sima, Image *ima, bool automati WM_main_add_notifier(NC_SPACE | ND_SPACE_IMAGE, NULL); } +void ED_space_image_sync(struct Main *bmain, struct Image *image, bool ignore_render_viewer) +{ + wmWindowManager *wm = (wmWindowManager *)bmain->wm.first; + LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { + const bScreen *screen = WM_window_get_active_screen(win); + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { + if (sl->spacetype != SPACE_IMAGE) { + continue; + } + SpaceImage *sima = (SpaceImage *)sl; + if (sima->pin) { + continue; + } + if (ignore_render_viewer && sima->image && + ELEM(sima->image->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE)) { + continue; + } + ED_space_image_set(bmain, sima, image, true); + } + } + } +} + void ED_space_image_auto_set(const bContext *C, SpaceImage *sima) { if (sima->mode != SI_MODE_UV || sima->pin) { diff --git a/source/blender/editors/space_node/add_menu_assets.cc b/source/blender/editors/space_node/add_menu_assets.cc index 1ba1d67d854..5458a25d74a 100644 --- a/source/blender/editors/space_node/add_menu_assets.cc +++ b/source/blender/editors/space_node/add_menu_assets.cc @@ -114,8 +114,11 @@ static AssetItemTree build_catalog_tree(const bContext &C, const bNodeTree *node if (BLI_uuid_is_nil(meta_data.catalog_id)) { return true; } - const LibraryCatalog &library_catalog = id_to_catalog_map.lookup(meta_data.catalog_id); - assets_per_path.add(library_catalog.catalog->path, LibraryAsset{library_ref, asset}); + const LibraryCatalog *library_catalog = id_to_catalog_map.lookup_ptr(meta_data.catalog_id); + if (library_catalog == nullptr) { + return true; + } + assets_per_path.add(library_catalog->catalog->path, LibraryAsset{library_ref, asset}); return true; }); } diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc index df31a0342cb..c66b8ad4ff0 100644 --- a/source/blender/editors/space_node/drawnode.cc +++ b/source/blender/editors/space_node/drawnode.cc @@ -1581,10 +1581,12 @@ void draw_nodespace_back_pix(const bContext &C, GPU_matrix_pop(); } -static float2 socket_link_connection_location(const bNodeSocket &socket, const bNodeLink &link) +static float2 socket_link_connection_location(const bNode &node, + const bNodeSocket &socket, + const bNodeLink &link) { const float2 socket_location(socket.locx, socket.locy); - if (socket.is_multi_input() && socket.is_input() && !(socket.owner_node().flag & NODE_HIDDEN)) { + if (socket.is_multi_input() && socket.is_input() && !(node.flag & NODE_HIDDEN)) { return node_link_calculate_multi_input_position( socket_location, link.multi_input_socket_index, socket.total_inputs); } @@ -1620,8 +1622,8 @@ static void calculate_inner_link_bezier_points(std::array<float2, 4> &points) static std::array<float2, 4> node_link_bezier_points(const bNodeLink &link) { std::array<float2, 4> points; - points[0] = socket_link_connection_location(*link.fromsock, link); - points[3] = socket_link_connection_location(*link.tosock, link); + points[0] = socket_link_connection_location(*link.fromnode, *link.fromsock, link); + points[3] = socket_link_connection_location(*link.tonode, *link.tosock, link); calculate_inner_link_bezier_points(points); return points; } @@ -2212,8 +2214,11 @@ static std::array<float2, 4> node_link_bezier_points_dragged(const SpaceNode &sn { const float2 cursor = snode.runtime->cursor * UI_DPI_FAC; std::array<float2, 4> points; - points[0] = link.fromsock ? socket_link_connection_location(*link.fromsock, link) : cursor; - points[3] = link.tosock ? socket_link_connection_location(*link.tosock, link) : cursor; + points[0] = link.fromsock ? + socket_link_connection_location(*link.fromnode, *link.fromsock, link) : + cursor; + points[3] = link.tosock ? socket_link_connection_location(*link.tonode, *link.tosock, link) : + cursor; calculate_inner_link_bezier_points(points); return points; } diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc index 48b3d711bdf..7982b47f363 100644 --- a/source/blender/editors/space_node/node_edit.cc +++ b/source/blender/editors/space_node/node_edit.cc @@ -89,8 +89,8 @@ struct CompoJob { Depsgraph *compositor_depsgraph; bNodeTree *localtree; /* Jon system integration. */ - const short *stop; - short *do_update; + const bool *stop; + bool *do_update; float *progress; }; @@ -166,7 +166,7 @@ static int compo_get_recalc_flags(const bContext *C) } /* called by compo, only to check job 'stop' value */ -static int compo_breakjob(void *cjv) +static bool compo_breakjob(void *cjv) { CompoJob *cj = (CompoJob *)cjv; @@ -250,8 +250,8 @@ static void compo_progressjob(void *cjv, float progress) static void compo_startjob(void *cjv, /* Cannot be const, this function implements wm_jobs_start_callback. * NOLINTNEXTLINE: readability-non-const-parameter. */ - short *stop, - short *do_update, + bool *stop, + bool *do_update, float *progress) { CompoJob *cj = (CompoJob *)cjv; @@ -502,6 +502,7 @@ void ED_node_shader_default(const bContext *C, ID *id) } ma->nodetree = ntreeCopyTree(bmain, ma_default->nodetree); + ma->nodetree->owner_id = &ma->id; BKE_ntree_update_main_tree(bmain, ma->nodetree, nullptr); } else if (ELEM(GS(id->name), ID_WO, ID_LA)) { @@ -736,26 +737,7 @@ void ED_node_set_active( * - current image is not a Render Result or ViewerNode (want to keep looking at these) */ if (node->id != nullptr && GS(node->id->name) == ID_IM) { Image *image = (Image *)node->id; - wmWindowManager *wm = (wmWindowManager *)bmain->wm.first; - LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { - const bScreen *screen = WM_window_get_active_screen(win); - LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { - LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { - if (sl->spacetype != SPACE_IMAGE) { - continue; - } - SpaceImage *sima = (SpaceImage *)sl; - if (sima->pin) { - continue; - } - if (sima->image && - ELEM(sima->image->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE)) { - continue; - } - ED_space_image_set(bmain, sima, image, true); - } - } - } + ED_space_image_sync(bmain, image, true); } if (r_active_texture_changed) { diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc index 637c795d4d7..8eeba8727dc 100644 --- a/source/blender/editors/space_node/node_relationships.cc +++ b/source/blender/editors/space_node/node_relationships.cc @@ -1678,6 +1678,7 @@ static int node_join_exec(bContext *C, wmOperator * /*op*/) const Set<bNode *> selected_nodes = get_selected_nodes(ntree); bNode *frame_node = nodeAddStaticNode(C, &ntree, NODE_FRAME); + nodeSetActive(&ntree, frame_node); /* reset tags */ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) { diff --git a/source/blender/editors/space_node/space_node.cc b/source/blender/editors/space_node/space_node.cc index 5754e77399f..c993fa57d76 100644 --- a/source/blender/editors/space_node/space_node.cc +++ b/source/blender/editors/space_node/space_node.cc @@ -5,6 +5,7 @@ * \ingroup spnode */ +#include "DNA_ID.h" #include "DNA_gpencil_types.h" #include "DNA_light_types.h" #include "DNA_material_types.h" @@ -28,6 +29,8 @@ #include "UI_resources.h" #include "UI_view2d.h" +#include "DEG_depsgraph.h" + #include "BLO_read_write.h" #include "RNA_access.h" @@ -181,7 +184,7 @@ void ED_node_tree_path_get(SpaceNode *snode, char *value) value += strlen(path->display_name); } else { - sprintf(value, "/%s", path->display_name); + BLI_sprintf(value, "/%s", path->display_name); value += strlen(path->display_name) + 1; } } @@ -191,6 +194,13 @@ void ED_node_set_active_viewer_key(SpaceNode *snode) { bNodeTreePath *path = (bNodeTreePath *)snode->treepath.last; if (snode->nodetree && path) { + /* A change in active viewer may result in the change of the output node used by the + * compositor, so we need to get notified about such changes. */ + if (snode->nodetree->active_viewer_key.value != path->parent_key.value) { + DEG_id_tag_update(&snode->nodetree->id, ID_RECALC_NTREE_OUTPUT); + WM_main_add_notifier(NC_NODE, nullptr); + } + snode->nodetree->active_viewer_key = path->parent_key; } } diff --git a/source/blender/editors/space_outliner/tree/tree_element_rna.cc b/source/blender/editors/space_outliner/tree/tree_element_rna.cc index 6e92fa087fb..275b4391d24 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_rna.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_rna.cc @@ -232,12 +232,13 @@ TreeElementRNAArrayElement::TreeElementRNAArrayElement(TreeElement &legacy_te, char c = RNA_property_array_item_char(TreeElementRNAArrayElement::getPropertyRNA(), index); - legacy_te_.name = static_cast<char *>(MEM_callocN(sizeof(char[20]), "OutlinerRNAArrayName")); + const size_t name_size = sizeof(char[20]); + legacy_te_.name = static_cast<char *>(MEM_callocN(name_size, "OutlinerRNAArrayName")); if (c) { - sprintf((char *)legacy_te_.name, " %c", c); + BLI_snprintf((char *)legacy_te_.name, name_size, " %c", c); } else { - sprintf((char *)legacy_te_.name, " %d", index + 1); + BLI_snprintf((char *)legacy_te_.name, name_size, " %d", index + 1); } legacy_te_.flag |= TE_FREE_NAME; } diff --git a/source/blender/editors/space_sequencer/sequencer_channels_draw.c b/source/blender/editors/space_sequencer/sequencer_channels_draw.c index 8abd7e424d1..901417c152f 100644 --- a/source/blender/editors/space_sequencer/sequencer_channels_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_channels_draw.c @@ -357,6 +357,10 @@ void draw_channels(const bContext *C, ARegion *region) SeqChannelDrawContext context; channel_draw_context_init(C, region, &context); + if (round_fl_to_int(context.channel_height) == 0) { + return; + } + UI_view2d_view_ortho(context.v2d); draw_channel_headers(&context); diff --git a/source/blender/editors/space_sequencer/sequencer_drag_drop.c b/source/blender/editors/space_sequencer/sequencer_drag_drop.c index c892e7d7e55..d43ce26d2a1 100644 --- a/source/blender/editors/space_sequencer/sequencer_drag_drop.c +++ b/source/blender/editors/space_sequencer/sequencer_drag_drop.c @@ -505,8 +505,8 @@ typedef struct DropJobData { } DropJobData; static void prefetch_data_fn(void *custom_data, - short *UNUSED(stop), - short *UNUSED(do_update), + bool *UNUSED(stop), + bool *UNUSED(do_update), float *UNUSED(progress)) { DropJobData *job_data = (DropJobData *)custom_data; diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index c0c7782c60c..a9e31de2096 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -371,7 +371,6 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op) else { /* SEQ_RIGHTSEL */ SEQ_time_right_handle_frame_set(scene, seq, snap_frame); } - SEQ_transform_fix_single_image_seq_offsets(scene, seq); } } } diff --git a/source/blender/editors/space_sequencer/sequencer_preview.c b/source/blender/editors/space_sequencer/sequencer_preview.c index 2820edc95aa..2410055d76d 100644 --- a/source/blender/editors/space_sequencer/sequencer_preview.c +++ b/source/blender/editors/space_sequencer/sequencer_preview.c @@ -51,7 +51,7 @@ static void free_preview_job(void *data) } /* Only this runs inside thread. */ -static void preview_startjob(void *data, short *stop, short *do_update, float *progress) +static void preview_startjob(void *data, bool *stop, bool *do_update, float *progress) { PreviewJob *pj = data; PreviewJobAudio *previewjb; diff --git a/source/blender/editors/space_sequencer/sequencer_proxy.c b/source/blender/editors/space_sequencer/sequencer_proxy.c index c851d3a29d4..30817771015 100644 --- a/source/blender/editors/space_sequencer/sequencer_proxy.c +++ b/source/blender/editors/space_sequencer/sequencer_proxy.c @@ -118,7 +118,7 @@ static int sequencer_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op)) if (seq->flag & SELECT) { ListBase queue = {NULL, NULL}; LinkData *link; - short stop = 0, do_update; + bool stop = false, do_update; float progress; SEQ_proxy_rebuild_context(bmain, depsgraph, scene, seq, file_list, &queue, false); @@ -126,7 +126,7 @@ static int sequencer_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op)) for (link = queue.first; link; link = link->next) { struct SeqIndexBuildContext *context = link->data; SEQ_proxy_rebuild(context, &stop, &do_update, &progress); - SEQ_proxy_rebuild_finish(context, 0); + SEQ_proxy_rebuild_finish(context, false); } SEQ_relations_free_imbuf(scene, &ed->seqbase, false); } diff --git a/source/blender/editors/space_sequencer/sequencer_thumbnails.c b/source/blender/editors/space_sequencer/sequencer_thumbnails.c index 460054f3b44..d1606b14152 100644 --- a/source/blender/editors/space_sequencer/sequencer_thumbnails.c +++ b/source/blender/editors/space_sequencer/sequencer_thumbnails.c @@ -132,8 +132,8 @@ static void seq_get_thumb_image_dimensions(Sequence *seq, } static void thumbnail_start_job(void *data, - short *stop, - short *UNUSED(do_update), + bool *stop, + bool *UNUSED(do_update), float *UNUSED(progress)) { ThumbnailDrawJob *tj = data; diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index f0196bf8e00..0ddd06ead62 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -3487,10 +3487,10 @@ static int text_insert_invoke(bContext *C, wmOperator *op, const wmEvent *event) /* NOTE: the "text" property is always set from key-map, * so we can't use #RNA_struct_property_is_set, check the length instead. */ if (!RNA_string_length(op->ptr, "text")) { - /* if alt/ctrl/super are pressed pass through except for utf8 character event + /* If Alt/Control/Super are pressed pass through except for utf8 character event * (when input method are used for utf8 inputs, the user may assign key event - * including alt/ctrl/super like ctrl+m to commit utf8 string. in such case, - * the modifiers in the utf8 character event make no sense.) */ + * including Alt/Control/Super like Control-M to commit utf8 string. + * In such case, the modifiers in the utf8 character event make no sense). */ if ((event->modifier & (KM_CTRL | KM_OSKEY)) && !event->utf8_buf[0]) { return OPERATOR_PASS_THROUGH; } diff --git a/source/blender/editors/space_view3d/view3d_draw.cc b/source/blender/editors/space_view3d/view3d_draw.cc index 31b26ba4cda..5d4ed032bb4 100644 --- a/source/blender/editors/space_view3d/view3d_draw.cc +++ b/source/blender/editors/space_view3d/view3d_draw.cc @@ -1306,15 +1306,15 @@ static void draw_selected_name( char info[300]; char *s = info; - s += sprintf(s, "(%d)", cfra); + s += BLI_sprintf(s, "(%d)", cfra); if ((ob == nullptr) || (ob->mode == OB_MODE_OBJECT)) { BKE_view_layer_synced_ensure(scene, view_layer); LayerCollection *layer_collection = BKE_view_layer_active_collection_get(view_layer); - s += sprintf(s, - " %s%s", - BKE_collection_ui_name_get(layer_collection->collection), - (ob == nullptr) ? "" : " |"); + s += BLI_sprintf(s, + " %s%s", + BKE_collection_ui_name_get(layer_collection->collection), + (ob == nullptr) ? "" : " |"); } /* Info can contain: @@ -1407,12 +1407,12 @@ static void draw_selected_name( } if (markern) { - s += sprintf(s, " <%s>", markern); + s += BLI_sprintf(s, " <%s>", markern); } if (v3d->flag2 & V3D_SHOW_VIEWER) { if (!BLI_listbase_is_empty(&v3d->viewer_path.path)) { - s += sprintf(s, "%s", IFACE_(" (Viewer)")); + s += BLI_sprintf(s, "%s", IFACE_(" (Viewer)")); } } diff --git a/source/blender/editors/space_view3d/view3d_select.cc b/source/blender/editors/space_view3d/view3d_select.cc index 765775c0b69..39ad6eb835a 100644 --- a/source/blender/editors/space_view3d/view3d_select.cc +++ b/source/blender/editors/space_view3d/view3d_select.cc @@ -2615,6 +2615,12 @@ static bool ed_object_select_pick(bContext *C, Base *basact = nullptr; const eObjectMode object_mode = oldbasact ? static_cast<eObjectMode>(oldbasact->object->mode) : OB_MODE_OBJECT; + /* For the most part this is equivalent to `(object_mode & OB_MODE_POSE) != 0` + * however this logic should also run with weight-paint + pose selection. + * Without this, selection in weight-paint mode can de-select armatures which isn't useful, + * see: T101686. */ + const bool has_pose_old = (oldbasact && + BKE_object_pose_armature_get_with_wpaint_check(oldbasact->object)); /* When enabled, don't attempt any further selection. */ bool handled = false; @@ -2653,7 +2659,7 @@ static bool ed_object_select_pick(bContext *C, * * This way prioritizing based on pose-mode has a bias to stay in pose-mode * without having to enforce this through locking the object mode. */ - bool do_bones_get_priotity = (object_mode & OB_MODE_POSE) != 0; + bool do_bones_get_priotity = has_pose_old; basact = (gpu->hits > 0) ? mouse_select_eval_buffer(&vc, gpu->buffer, @@ -2665,10 +2671,14 @@ static bool ed_object_select_pick(bContext *C, nullptr; } + /* See comment for `has_pose_old`, the same rationale applies here. */ + const bool has_pose_new = (basact && + BKE_object_pose_armature_get_with_wpaint_check(basact->object)); + /* Select pose-bones or camera-tracks. */ if (((gpu->hits > 0) && gpu->has_bones) || /* Special case, even when there are no hits, pose logic may de-select all bones. */ - ((gpu->hits == 0) && (object_mode & OB_MODE_POSE))) { + ((gpu->hits == 0) && has_pose_old)) { if (basact && (gpu->has_bones && (basact->object->type == OB_CAMERA))) { MovieClip *clip = BKE_object_movieclip_get(scene, basact->object, false); @@ -2728,7 +2738,7 @@ static bool ed_object_select_pick(bContext *C, handled = true; } - else if ((object_mode & OB_MODE_POSE) && (basact->object->mode & OB_MODE_POSE)) { + else if (has_pose_old && has_pose_new) { /* Within pose-mode, keep the current selection when switching pose bones, * this is noticeable when in pose mode with multiple objects at once. * Where selecting the bone of a different object would de-select this one. @@ -2954,6 +2964,9 @@ static bool ed_wpaint_vertex_select_pick(bContext *C, changed = true; } + else { + select_vert.finish(); + } if (changed) { paintvert_tag_select_update(C, obact); diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c index 090f1bf1e6c..80c74b81cfa 100644 --- a/source/blender/editors/transform/transform_convert_sequencer.c +++ b/source/blender/editors/transform/transform_convert_sequencer.c @@ -615,7 +615,6 @@ static void flushTransSeq(TransInfo *t) case SEQ_LEFTSEL: { /* No vertical transform. */ int old_startdisp = SEQ_time_left_handle_frame_get(scene, seq); SEQ_time_left_handle_frame_set(t->scene, seq, new_frame); - SEQ_transform_fix_single_image_seq_offsets(t->scene, seq); if (abs(SEQ_time_left_handle_frame_get(scene, seq) - old_startdisp) > abs(max_offset)) { max_offset = SEQ_time_left_handle_frame_get(scene, seq) - old_startdisp; @@ -625,7 +624,6 @@ static void flushTransSeq(TransInfo *t) case SEQ_RIGHTSEL: { /* No vertical transform. */ int old_enddisp = SEQ_time_right_handle_frame_get(scene, seq); SEQ_time_right_handle_frame_set(t->scene, seq, new_frame); - SEQ_transform_fix_single_image_seq_offsets(t->scene, seq); if (abs(SEQ_time_right_handle_frame_get(scene, seq) - old_enddisp) > abs(max_offset)) { max_offset = SEQ_time_right_handle_frame_get(scene, seq) - old_enddisp; diff --git a/source/blender/editors/transform/transform_snap_object.cc b/source/blender/editors/transform/transform_snap_object.cc index d1cf7487c51..598b3f7f1b7 100644 --- a/source/blender/editors/transform/transform_snap_object.cc +++ b/source/blender/editors/transform/transform_snap_object.cc @@ -35,6 +35,7 @@ #include "BKE_layer.h" #include "BKE_mesh.h" #include "BKE_mesh_runtime.h" +#include "BKE_mesh_wrapper.h" #include "BKE_object.h" #include "BKE_tracking.h" @@ -61,41 +62,6 @@ enum eViewProj { VIEW_PROJ_PERSP = -1, }; -/* SnapObjectContext.cache.mesh_map */ -struct SnapData_Mesh { - /* Loose edges, loose verts. */ - BVHTree *bvhtree[2]; - bool cached[2]; - - /* Looptris. */ - BVHTreeFromMesh treedata_mesh; - - const MPoly *poly; - bool has_looptris; - bool has_loose_edge; - bool has_loose_vert; - - void clear() - { - for (int i = 0; i < ARRAY_SIZE(this->bvhtree); i++) { - if (!this->cached[i]) { - BLI_bvhtree_free(this->bvhtree[i]); - } - this->bvhtree[i] = nullptr; - } - free_bvhtree_from_mesh(&this->treedata_mesh); - } - - ~SnapData_Mesh() - { - this->clear(); - } - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("SnapData_Mesh") -#endif -}; - /* SnapObjectContext.cache.editmesh_map */ struct SnapData_EditMesh { /* Verts, Edges. */ @@ -134,7 +100,6 @@ struct SnapObjectContext { int flag; - Map<const Object *, std::unique_ptr<SnapData_Mesh>> mesh_caches; Map<const BMEditMesh *, std::unique_ptr<SnapData_EditMesh>> editmesh_caches; /* Filter data, returns true to check this value */ @@ -161,6 +126,28 @@ struct SnapObjectContext { eSnapMode snap_to_flag; bool has_occlusion_plane; /* Ignore plane of occlusion in curves. */ } runtime; + + /* Output. */ + struct { + /* Location of snapped point on target surface. */ + float loc[3]; + /* Normal of snapped point on target surface. */ + float no[3]; + /* Index of snapped element on target object (-1 when no valid index is found). */ + int index; + /* Matrix of target object (may not be #Object.object_to_world with dupli-instances). */ + float obmat[4][4]; + /* List of #SnapObjectHitDepth (caller must free). */ + ListBase *hit_list; + /* Snapped object. */ + Object *ob; + /* Snapped data. */ + ID *data; + + float dist_sq; + + bool is_edit; + } ret; }; /** \} */ @@ -176,37 +163,48 @@ struct SnapObjectContext { * - In rare cases there is no evaluated mesh available and a null result doesn't imply an * edit-mesh, so callers need to account for a null edit-mesh too, see: T96536. */ -static const Mesh *mesh_for_snap(Object *ob_eval, eSnapEditType edit_mode_type, bool *r_use_hide) +static ID *data_for_snap(Object *ob_eval, eSnapEditType edit_mode_type, bool *r_use_hide) { - const Mesh *me_eval = BKE_object_get_evaluated_mesh(ob_eval); bool use_hide = false; - if (BKE_object_is_in_editmode(ob_eval)) { - if (edit_mode_type == SNAP_GEOM_EDIT) { - return nullptr; - } - const Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob_eval); - const Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob_eval); + switch (ob_eval->type) { + case OB_MESH: { + Mesh *me_eval = BKE_object_get_evaluated_mesh(ob_eval); + if (BKE_object_is_in_editmode(ob_eval)) { + if (edit_mode_type == SNAP_GEOM_EDIT) { + return nullptr; + } + + Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob_eval); + Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob_eval); - if ((edit_mode_type == SNAP_GEOM_FINAL) && editmesh_eval_final) { - if (editmesh_eval_final->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH) { - return nullptr; + if ((edit_mode_type == SNAP_GEOM_FINAL) && editmesh_eval_final) { + if (editmesh_eval_final->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH) { + return nullptr; + } + me_eval = editmesh_eval_final; + use_hide = true; + } + else if ((edit_mode_type == SNAP_GEOM_CAGE) && editmesh_eval_cage) { + if (editmesh_eval_cage->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH) { + return nullptr; + } + me_eval = editmesh_eval_cage; + use_hide = true; + } } - me_eval = editmesh_eval_final; - use_hide = true; - } - else if ((edit_mode_type == SNAP_GEOM_CAGE) && editmesh_eval_cage) { - if (editmesh_eval_cage->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH) { - return nullptr; + if (r_use_hide) { + *r_use_hide = use_hide; } - me_eval = editmesh_eval_cage; - use_hide = true; + return (ID *)me_eval; } + default: + break; } if (r_use_hide) { *r_use_hide = use_hide; } - return me_eval; + return (ID *)ob_eval->data; } /** \} */ @@ -236,98 +234,31 @@ static void snap_editmesh_minmax(SnapObjectContext *sctx, } } -static SnapData_Mesh *snap_object_data_mesh_get(SnapObjectContext *sctx, - Object *ob_eval, - const Mesh *me_eval, - bool use_hide) +static void snap_object_data_mesh_get(SnapObjectContext *sctx, + Object *ob_eval, + const Mesh *me_eval, + bool use_hide, + BVHTreeFromMesh *r_treedata) { - SnapData_Mesh *sod; - bool init = false; - const Span<float3> positions = me_eval->positions(); - const Span<MEdge> edges = me_eval->edges(); const Span<MPoly> polys = me_eval->polys(); const Span<MLoop> loops = me_eval->loops(); - if (std::unique_ptr<SnapData_Mesh> *sod_p = sctx->mesh_caches.lookup_ptr(ob_eval)) { - sod = sod_p->get(); - bool is_dirty = false; - if (sod->treedata_mesh.tree && sod->treedata_mesh.cached && - !bvhcache_has_tree(me_eval->runtime->bvh_cache, sod->treedata_mesh.tree)) { - /* The tree is owned by the Mesh and may have been freed since we last used. */ - is_dirty = true; - } - else if (sod->bvhtree[0] && sod->cached[0] && - !bvhcache_has_tree(me_eval->runtime->bvh_cache, sod->bvhtree[0])) { - /* The tree is owned by the Mesh and may have been freed since we last used. */ - is_dirty = true; - } - else if (sod->bvhtree[1] && sod->cached[1] && - !bvhcache_has_tree(me_eval->runtime->bvh_cache, sod->bvhtree[1])) { - /* The tree is owned by the Mesh and may have been freed since we last used. */ - is_dirty = true; - } - else if (sod->treedata_mesh.looptri != me_eval->looptris().data()) { - is_dirty = true; - } - else if (sod->treedata_mesh.positions != - reinterpret_cast<const float(*)[3]>(positions.data())) { - is_dirty = true; - } - else if (sod->treedata_mesh.loop != loops.data()) { - is_dirty = true; - } - else if (sod->treedata_mesh.edge != edges.data()) { - is_dirty = true; - } - else if (sod->poly != polys.data()) { - is_dirty = true; - } - - if (is_dirty) { - sod->clear(); - init = true; - } - } - else { - if (ob_eval->type == OB_MESH) { - /* Any existing #SnapData_EditMesh is now invalid. */ - sctx->editmesh_caches.remove(BKE_editmesh_from_object(ob_eval)); - } - - std::unique_ptr<SnapData_Mesh> sod_ptr = std::make_unique<SnapData_Mesh>(); - sod = sod_ptr.get(); - sctx->mesh_caches.add_new(ob_eval, std::move(sod_ptr)); - - init = true; + if (ob_eval->type == OB_MESH) { + /* Any existing #SnapData_EditMesh is now invalid. */ + sctx->editmesh_caches.remove(BKE_editmesh_from_object(ob_eval)); } - if (init) { - /* The BVHTree from looptris is always required. */ - BLI_assert(sod->treedata_mesh.tree == nullptr); - BKE_bvhtree_from_mesh_get(&sod->treedata_mesh, - me_eval, - use_hide ? BVHTREE_FROM_LOOPTRI_NO_HIDDEN : BVHTREE_FROM_LOOPTRI, - 4); - - BLI_assert(sod->treedata_mesh.positions == - reinterpret_cast<const float(*)[3]>(positions.data())); - BLI_assert(!positions.data() || sod->treedata_mesh.vert_normals); - BLI_assert(sod->treedata_mesh.loop == loops.data()); - BLI_assert(!polys.data() || sod->treedata_mesh.looptri); + /* The BVHTree from looptris is always required. */ + BKE_bvhtree_from_mesh_get( + r_treedata, me_eval, use_hide ? BVHTREE_FROM_LOOPTRI_NO_HIDDEN : BVHTREE_FROM_LOOPTRI, 4); - sod->has_looptris = sod->treedata_mesh.tree != nullptr; + BLI_assert(r_treedata.vert == positions.data()); + BLI_assert(!positions.data() || r_treedata.vert_normals); + BLI_assert(r_treedata.loop == loops.data()); + BLI_assert(!polys.data() || r_treedata.looptri); - /* Required for snapping with occlusion. */ - sod->treedata_mesh.edge = edges.data(); - sod->poly = polys.data(); - - /* Start assuming that it has each of these element types. */ - sod->has_loose_edge = true; - sod->has_loose_vert = true; - } - - return sod; + UNUSED_VARS_NDEBUG(positions, polys, loops); } /* Searches for the #Mesh_Runtime associated with the object that is most likely to be updated due @@ -354,9 +285,6 @@ static SnapData_EditMesh *snap_object_data_editmesh_get(SnapObjectContext *sctx, SnapData_EditMesh *sod; bool init = false; - /* Any existing #SnapData_Mesh is now invalid. */ - sctx->mesh_caches.remove(ob_eval); - if (std::unique_ptr<SnapData_EditMesh> *sod_p = sctx->editmesh_caches.lookup_ptr(em)) { sod = sod_p->get(); bool is_dirty = false; @@ -413,15 +341,6 @@ static SnapData_EditMesh *snap_object_data_editmesh_get(SnapObjectContext *sctx, return sod; } -static BVHTreeFromMesh *snap_object_data_mesh_treedata_get(SnapObjectContext *sctx, - Object *ob_eval, - const Mesh *me_eval, - bool use_hide) -{ - SnapData_Mesh *sod = snap_object_data_mesh_get(sctx, ob_eval, me_eval, use_hide); - return &sod->treedata_mesh; -} - static BVHTreeFromEditMesh *snap_object_data_editmesh_treedata_get(SnapObjectContext *sctx, Object *ob_eval, BMEditMesh *em) @@ -475,12 +394,14 @@ static BVHTreeFromEditMesh *snap_object_data_editmesh_treedata_get(SnapObjectCon /** \name Iterator * \{ */ -using IterSnapObjsCallback = void (*)(SnapObjectContext *sctx, - const SnapObjectParams *params, - Object *ob_eval, - const float obmat[4][4], - bool is_object_active, - void *data); +using IterSnapObjsCallback = eSnapMode (*)(SnapObjectContext *sctx, + const SnapObjectParams *params, + Object *ob_eval, + ID *ob_data, + const float obmat[4][4], + bool is_object_active, + bool use_hide, + void *data); static bool snap_object_is_snappable(const SnapObjectContext *sctx, const eSnapTargetSelect snap_target_select, @@ -540,11 +461,14 @@ static bool snap_object_is_snappable(const SnapObjectContext *sctx, /** * Walks through all objects in the scene to create the list of objects to snap. */ -static void iter_snap_objects(SnapObjectContext *sctx, - const SnapObjectParams *params, - IterSnapObjsCallback sob_callback, - void *data) +static eSnapMode iter_snap_objects(SnapObjectContext *sctx, + const SnapObjectParams *params, + IterSnapObjsCallback sob_callback, + void *data) { + eSnapMode ret = SCE_SNAP_MODE_NONE; + eSnapMode tmp; + Scene *scene = DEG_get_input_scene(sctx->runtime.depsgraph); ViewLayer *view_layer = DEG_get_input_view_layer(sctx->runtime.depsgraph); const eSnapTargetSelect snap_target_select = params->snap_target_select; @@ -562,13 +486,34 @@ static void iter_snap_objects(SnapObjectContext *sctx, ListBase *lb = object_duplilist(sctx->runtime.depsgraph, sctx->scene, obj_eval); LISTBASE_FOREACH (DupliObject *, dupli_ob, lb) { BLI_assert(DEG_is_evaluated_object(dupli_ob->ob)); - sob_callback(sctx, params, dupli_ob->ob, dupli_ob->mat, is_object_active, data); + if ((tmp = sob_callback(sctx, + params, + dupli_ob->ob, + dupli_ob->ob_data, + dupli_ob->mat, + is_object_active, + false, + data)) != SCE_SNAP_MODE_NONE) { + ret = tmp; + } } free_object_duplilist(lb); } - sob_callback(sctx, params, obj_eval, obj_eval->object_to_world, is_object_active, data); + bool use_hide = false; + ID *ob_data = data_for_snap(obj_eval, params->edit_mode_type, &use_hide); + if ((tmp = sob_callback(sctx, + params, + obj_eval, + ob_data, + obj_eval->object_to_world, + is_object_active, + use_hide, + data)) != SCE_SNAP_MODE_NONE) { + ret = tmp; + } } + return ret; } /** \} */ @@ -769,14 +714,17 @@ static bool raycastMesh(SnapObjectContext *sctx, } /* Test BoundBox */ - const BoundBox *bb = BKE_object_boundbox_get(ob_eval); - if (bb) { - /* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */ - if (!isect_ray_aabb_v3_simple( - ray_start_local, ray_normal_local, bb->vec[0], bb->vec[6], &len_diff, nullptr)) { - return retval; + if (ob_eval->data == me_eval) { + const BoundBox *bb = BKE_object_boundbox_get(ob_eval); + if (bb) { + /* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */ + if (!isect_ray_aabb_v3_simple( + ray_start_local, ray_normal_local, bb->vec[0], bb->vec[6], &len_diff, nullptr)) { + return retval; + } } } + /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with * very far away ray_start values (as returned in case of ortho view3d), see T50486, T38358. */ @@ -789,23 +737,22 @@ static bool raycastMesh(SnapObjectContext *sctx, len_diff = 0.0f; } - SnapData_Mesh *sod = snap_object_data_mesh_get(sctx, ob_eval, me_eval, use_hide); + BVHTreeFromMesh treedata; + snap_object_data_mesh_get(sctx, ob_eval, me_eval, use_hide, &treedata); - BVHTreeFromMesh *treedata = &sod->treedata_mesh; - - if (treedata->tree == nullptr) { + if (treedata.tree == nullptr) { return retval; } float timat[3][3]; /* transpose inverse matrix for normals */ transpose_m3_m4(timat, imat); - BLI_assert(treedata->raycast_callback != nullptr); + BLI_assert(treedata.raycast_callback != nullptr); if (r_hit_list) { RayCastAll_Data data; - data.bvhdata = treedata; - data.raycast_callback = treedata->raycast_callback; + data.bvhdata = &treedata; + data.raycast_callback = treedata.raycast_callback; data.obmat = obmat; data.timat = timat; data.len_diff = len_diff; @@ -815,13 +762,8 @@ static bool raycastMesh(SnapObjectContext *sctx, data.hit_list = r_hit_list; data.retval = retval; - BLI_bvhtree_ray_cast_all(treedata->tree, - ray_start_local, - ray_normal_local, - 0.0f, - *ray_depth, - raycast_all_cb, - &data); + BLI_bvhtree_ray_cast_all( + treedata.tree, ray_start_local, ray_normal_local, 0.0f, *ray_depth, raycast_all_cb, &data); retval = data.retval; } @@ -830,15 +772,15 @@ static bool raycastMesh(SnapObjectContext *sctx, hit.index = -1; hit.dist = local_depth; - if (BLI_bvhtree_ray_cast(treedata->tree, + if (BLI_bvhtree_ray_cast(treedata.tree, ray_start_local, ray_normal_local, 0.0f, &hit, params->use_backface_culling ? mesh_looptri_raycast_backface_culling_cb : - treedata->raycast_callback, - treedata) != -1) { + treedata.raycast_callback, + &treedata) != -1) { hit.dist += len_diff; hit.dist /= local_scale; if (hit.dist <= *ray_depth) { @@ -857,7 +799,7 @@ static bool raycastMesh(SnapObjectContext *sctx, retval = true; if (r_index) { - *r_index = treedata->looptri[hit.index].poly; + *r_index = treedata.looptri[hit.index].poly; } } } @@ -1009,26 +951,21 @@ struct RaycastObjUserData { uint ob_index; /* read/write args */ float *ray_depth; - /* return args */ - float *r_loc; - float *r_no; - int *r_index; - Object **r_ob; - float (*r_obmat)[4]; - ListBase *r_hit_list; + bool use_occlusion_test; - bool ret; }; /** * \note Duplicate args here are documented at #snapObjectsRay */ -static void raycast_obj_fn(SnapObjectContext *sctx, - const SnapObjectParams *params, - Object *ob_eval, - const float obmat[4][4], - bool is_object_active, - void *data) +static eSnapMode raycast_obj_fn(SnapObjectContext *sctx, + const SnapObjectParams *params, + Object *ob_eval, + ID *ob_data, + const float obmat[4][4], + bool is_object_active, + bool use_hide, + void *data) { RaycastObjUserData *dt = static_cast<RaycastObjUserData *>(data); const uint ob_index = dt->ob_index++; @@ -1037,92 +974,74 @@ static void raycast_obj_fn(SnapObjectContext *sctx, float *ray_depth = dt->ray_depth; bool retval = false; + bool is_edit = false; if (use_occlusion_test) { if (ELEM(ob_eval->dt, OB_BOUNDBOX, OB_WIRE)) { /* Do not hit objects that are in wire or bounding box * display mode. */ - return; + return SCE_SNAP_MODE_NONE; } } - switch (ob_eval->type) { - case OB_MESH: { - const eSnapEditType edit_mode_type = params->edit_mode_type; - bool use_hide = false; - const Mesh *me_eval = mesh_for_snap(ob_eval, edit_mode_type, &use_hide); - if (me_eval == nullptr) { - BMEditMesh *em = BKE_editmesh_from_object(ob_eval); - if (UNLIKELY(!em)) { /* See #mesh_for_snap doc-string. */ - return; - } - BLI_assert_msg(em == BKE_editmesh_from_object(DEG_get_original_object(ob_eval)), - "Make sure there is only one pointer for looptris"); - retval = raycastEditMesh(sctx, - params, - dt->ray_start, - dt->ray_dir, - ob_eval, - em, - obmat, - ob_index, - ray_depth, - dt->r_loc, - dt->r_no, - dt->r_index, - dt->r_hit_list); - break; + if (ob_data == nullptr) { + if (ob_eval->type == OB_MESH) { + BMEditMesh *em = BKE_editmesh_from_object(ob_eval); + if (UNLIKELY(!em)) { /* See #mesh_for_snap doc-string. */ + return SCE_SNAP_MODE_NONE; } - retval = raycastMesh(sctx, - params, - dt->ray_start, - dt->ray_dir, - ob_eval, - me_eval, - obmat, - ob_index, - use_hide, - ray_depth, - dt->r_loc, - dt->r_no, - dt->r_index, - dt->r_hit_list); - break; - } - case OB_CURVES_LEGACY: - case OB_SURF: - case OB_FONT: { - if (!is_object_active) { - const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval); - if (mesh_eval) { - retval = raycastMesh(sctx, - params, - dt->ray_start, - dt->ray_dir, - ob_eval, - mesh_eval, - obmat, - ob_index, - false, - ray_depth, - dt->r_loc, - dt->r_no, - dt->r_index, - dt->r_hit_list); - } + if (raycastEditMesh(sctx, + params, + dt->ray_start, + dt->ray_dir, + ob_eval, + em, + obmat, + ob_index, + ray_depth, + sctx->ret.loc, + sctx->ret.no, + &sctx->ret.index, + sctx->ret.hit_list)) { + retval = true; + is_edit = true; } - break; } + else { + return SCE_SNAP_MODE_NONE; + } + } + else if (GS(ob_data->name) != ID_ME) { + return SCE_SNAP_MODE_NONE; + } + else if (is_object_active && ELEM(ob_eval->type, OB_CURVES_LEGACY, OB_SURF, OB_FONT)) { + return SCE_SNAP_MODE_NONE; + } + else { + const Mesh *me_eval = (const Mesh *)ob_data; + retval = raycastMesh(sctx, + params, + dt->ray_start, + dt->ray_dir, + ob_eval, + me_eval, + obmat, + ob_index, + use_hide, + ray_depth, + sctx->ret.loc, + sctx->ret.no, + &sctx->ret.index, + sctx->ret.hit_list); } if (retval) { - if (dt->r_ob) { - *dt->r_ob = ob_eval; - } - if (dt->r_obmat) { - copy_m4_m4(dt->r_obmat, obmat); - } - dt->ret = true; + copy_m4_m4(sctx->ret.obmat, obmat); + sctx->ret.ob = ob_eval; + sctx->ret.data = ob_data; + sctx->ret.is_edit = is_edit; + return SCE_SNAP_MODE_FACE_RAYCAST; } + return SCE_SNAP_MODE_NONE; } /** @@ -1138,17 +1057,6 @@ static void raycast_obj_fn(SnapObjectContext *sctx, * * \param ray_depth: maximum depth allowed for r_co, * elements deeper than this value will be ignored. - * - * Output Args - * ----------- - * - * \param r_loc: Hit location. - * \param r_no: Hit normal (optional). - * \param r_index: Hit index or -1 when no valid index is found. - * (currently only set to the polygon index when using `snap_to == SCE_SNAP_MODE_FACE_RAYCAST`). - * \param r_ob: Hit object. - * \param r_obmat: Object matrix (may not be #Object.object_to_world with dupli-instances). - * \param r_hit_list: List of #SnapObjectHitDepth (caller must free). */ static bool raycastObjects(SnapObjectContext *sctx, const SnapObjectParams *params, @@ -1157,14 +1065,7 @@ static bool raycastObjects(SnapObjectContext *sctx, /* read/write args */ /* Parameters below cannot be const, because they are assigned to a * non-const variable (readability-non-const-parameter). */ - float *ray_depth /* NOLINT */, - /* return args */ - float r_loc[3] /* NOLINT */, - float r_no[3] /* NOLINT */, - int *r_index /* NOLINT */, - Object **r_ob, - float r_obmat[4][4], - ListBase *r_hit_list) + float *ray_depth /* NOLINT */) { const View3D *v3d = sctx->runtime.v3d; if (params->use_occlusion_test && v3d && XRAY_FLAG_ENABLED(v3d)) { @@ -1180,18 +1081,9 @@ static bool raycastObjects(SnapObjectContext *sctx, data.ray_dir = ray_dir; data.ob_index = 0; data.ray_depth = ray_depth; - data.r_loc = r_loc; - data.r_no = r_no; - data.r_index = r_index; - data.r_ob = r_ob; - data.r_obmat = r_obmat; - data.r_hit_list = r_hit_list; data.use_occlusion_test = params->use_occlusion_test; - data.ret = false; - iter_snap_objects(sctx, params, raycast_obj_fn, &data); - - return data.ret; + return iter_snap_objects(sctx, params, raycast_obj_fn, &data) != SCE_SNAP_MODE_NONE; } /** \} */ @@ -1203,15 +1095,6 @@ static bool raycastObjects(SnapObjectContext *sctx, struct NearestWorldObjUserData { const float *init_co; const float *curr_co; - /* return args */ - float *r_loc; - float *r_no; - int *r_index; - float r_dist_sq; - Object **r_ob; - float (*r_obmat)[4]; - ListBase *r_hit_list; - bool ret; }; static void nearest_world_tree_co(BVHTree *tree, @@ -1300,14 +1183,13 @@ static bool nearest_world_tree(SnapObjectContext * /*sctx*/, float co_local[3]; float no_local[3]; - int index; copy_v3_v3(co_local, init_co_local); for (int i = 0; i < params->face_nearest_steps; i++) { add_v3_v3(co_local, delta_local); nearest_world_tree_co( - tree, nearest_cb, treedata, co_local, co_local, no_local, &index, nullptr); + tree, nearest_cb, treedata, co_local, co_local, no_local, r_index, nullptr); } mul_v3_m4v3(r_loc, obmat, co_local); @@ -1317,10 +1199,6 @@ static bool nearest_world_tree(SnapObjectContext * /*sctx*/, normalize_v3(r_no); } - if (r_index) { - *r_index = index; - } - return true; } @@ -1337,16 +1215,17 @@ static bool nearest_world_mesh(SnapObjectContext *sctx, float *r_no, int *r_index) { - BVHTreeFromMesh *treedata = snap_object_data_mesh_treedata_get(sctx, ob_eval, me_eval, use_hide); - if (treedata == nullptr || treedata->tree == nullptr) { + BVHTreeFromMesh treedata; + snap_object_data_mesh_get(sctx, ob_eval, me_eval, use_hide, &treedata); + if (treedata.tree == nullptr) { return false; } return nearest_world_tree(sctx, params, - treedata->tree, - treedata->nearest_callback, - treedata, + treedata.tree, + treedata.nearest_callback, + &treedata, obmat, init_co, curr_co, @@ -1386,85 +1265,75 @@ static bool nearest_world_editmesh(SnapObjectContext *sctx, r_no, r_index); } -static void nearest_world_object_fn(SnapObjectContext *sctx, - const struct SnapObjectParams *params, - Object *ob_eval, - const float obmat[4][4], - bool is_object_active, - void *data) +static eSnapMode nearest_world_object_fn(SnapObjectContext *sctx, + const SnapObjectParams *params, + Object *ob_eval, + ID *ob_data, + const float obmat[4][4], + bool is_object_active, + bool use_hide, + void *data) { struct NearestWorldObjUserData *dt = static_cast<NearestWorldObjUserData *>(data); bool retval = false; - switch (ob_eval->type) { - case OB_MESH: { - const eSnapEditType edit_mode_type = params->edit_mode_type; - bool use_hide = false; - const Mesh *me_eval = mesh_for_snap(ob_eval, edit_mode_type, &use_hide); - if (me_eval) { - retval = nearest_world_mesh(sctx, - params, - ob_eval, - me_eval, - obmat, - use_hide, - dt->init_co, - dt->curr_co, - &dt->r_dist_sq, - dt->r_loc, - dt->r_no, - dt->r_index); + bool is_edit = false; + + if (ob_data == nullptr) { + if (ob_eval->type == OB_MESH) { + BMEditMesh *em = BKE_editmesh_from_object(ob_eval); + if (UNLIKELY(!em)) { /* See #data_for_snap doc-string. */ + return SCE_SNAP_MODE_NONE; } - else { - BMEditMesh *em = BKE_editmesh_from_object(ob_eval); - BLI_assert_msg(em == BKE_editmesh_from_object(DEG_get_original_object(ob_eval)), - "Make sure there is only one pointer for looptris"); - retval = nearest_world_editmesh(sctx, - params, - ob_eval, - em, - obmat, - dt->init_co, - dt->curr_co, - &dt->r_dist_sq, - dt->r_loc, - dt->r_no, - dt->r_index); + if (nearest_world_editmesh(sctx, + params, + ob_eval, + em, + obmat, + dt->init_co, + dt->curr_co, + &sctx->ret.dist_sq, + sctx->ret.loc, + sctx->ret.no, + &sctx->ret.index)) { + retval = true; + is_edit = true; } - break; } - case OB_CURVES_LEGACY: - case OB_SURF: - case OB_FONT: - if (!is_object_active) { - const Mesh *me_eval = BKE_object_get_evaluated_mesh(ob_eval); - if (me_eval) { - retval = nearest_world_mesh(sctx, - params, - ob_eval, - me_eval, - obmat, - false, - dt->init_co, - dt->curr_co, - &dt->r_dist_sq, - dt->r_loc, - dt->r_no, - dt->r_index); - } - } - break; + else { + return SCE_SNAP_MODE_NONE; + } + } + else if (GS(ob_data) != ID_ME) { + return SCE_SNAP_MODE_NONE; + } + else if (is_object_active && ELEM(ob_eval->type, OB_CURVES_LEGACY, OB_SURF, OB_FONT)) { + return SCE_SNAP_MODE_NONE; + } + else { + const Mesh *me_eval = (const Mesh *)ob_data; + retval = nearest_world_mesh(sctx, + params, + ob_eval, + me_eval, + obmat, + use_hide, + dt->init_co, + dt->curr_co, + &sctx->ret.dist_sq, + sctx->ret.loc, + sctx->ret.no, + &sctx->ret.index); } if (retval) { - if (dt->r_ob) { - *dt->r_ob = ob_eval; - } - if (dt->r_obmat) { - copy_m4_m4(dt->r_obmat, obmat); - } - dt->ret = true; + copy_m4_m4(sctx->ret.obmat, obmat); + sctx->ret.ob = ob_eval; + sctx->ret.data = ob_data; + sctx->ret.is_edit = is_edit; + return SCE_SNAP_MODE_FACE_NEAREST; } + return SCE_SNAP_MODE_NONE; } /** @@ -1477,39 +1346,17 @@ static void nearest_world_object_fn(SnapObjectContext *sctx, * \param params: Settings for snapping. * \param init_co: Initial location of source point. * \param prev_co: Current location of source point after transformation but before snapping. - * - * Output Args - * ----------- - * - * \param r_loc: Location of nearest point on target surface. - * \param r_no: Normal of nearest point on target surface. - * \param r_index: Index of nearest polygon on target surface. - * \param r_ob: Nearest target object. - * \param r_obmat: Nearest target matrix (may not be #Object.object_to_world with dupli-instances). */ static bool nearestWorldObjects(SnapObjectContext *sctx, const struct SnapObjectParams *params, const float init_co[3], - const float curr_co[3], - float *r_loc /* NOLINT */, - float *r_no /* NOLINT */, - int *r_index /* NOLINT */, - Object **r_ob, - float r_obmat[4][4]) + const float curr_co[3]) { NearestWorldObjUserData data = {}; data.init_co = init_co; data.curr_co = curr_co; - data.r_loc = r_loc; - data.r_no = r_no; - data.r_index = r_index; - data.r_dist_sq = FLT_MAX; - data.r_ob = r_ob; - data.r_obmat = r_obmat; - data.ret = false; - - iter_snap_objects(sctx, params, nearest_world_object_fn, &data); - return data.ret; + + return iter_snap_objects(sctx, params, nearest_world_object_fn, &data) != SCE_SNAP_MODE_NONE; } /** \} */ @@ -1856,7 +1703,7 @@ static void cb_snap_tri_verts(void *userdata, } } -static void nearest2d_data_init_mesh(SnapData_Mesh *sod, +static void nearest2d_data_init_mesh(const Mesh *mesh, bool is_persp, bool use_backface_culling, Nearest2dUserData *r_nearest2d) @@ -1867,11 +1714,11 @@ static void nearest2d_data_init_mesh(SnapData_Mesh *sod, r_nearest2d->get_tri_verts_index = cb_mlooptri_verts_get; r_nearest2d->get_tri_edges_index = cb_mlooptri_edges_get; - r_nearest2d->positions = sod->treedata_mesh.positions; - r_nearest2d->vert_normals = sod->treedata_mesh.vert_normals; - r_nearest2d->edge = sod->treedata_mesh.edge; - r_nearest2d->loop = sod->treedata_mesh.loop; - r_nearest2d->looptri = sod->treedata_mesh.looptri; + r_nearest2d->positions = BKE_mesh_positions(mesh); + r_nearest2d->vert_normals = BKE_mesh_vertex_normals_ensure(mesh); + r_nearest2d->edge = mesh->edges().data(); + r_nearest2d->loop = mesh->loops().data(); + r_nearest2d->looptri = BKE_mesh_runtime_looptri_ensure(mesh); r_nearest2d->is_persp = is_persp; r_nearest2d->use_backface_culling = use_backface_culling; @@ -1902,26 +1749,20 @@ static void nearest2d_data_init_editmesh(SnapData_EditMesh *sod, static eSnapMode snap_mesh_polygon(SnapObjectContext *sctx, const SnapObjectParams *params, - Object *ob_eval, - const float obmat[4][4], /* read/write args */ - float *dist_px, - /* return args */ - float r_loc[3], - float r_no[3], - int *r_index) + float *dist_px) { eSnapMode elem = SCE_SNAP_MODE_NONE; float lpmat[4][4]; - mul_m4_m4m4(lpmat, sctx->runtime.pmat, obmat); + mul_m4_m4m4(lpmat, sctx->runtime.pmat, sctx->ret.obmat); DistProjectedAABBPrecalc neasrest_precalc; dist_squared_to_projected_aabb_precalc( &neasrest_precalc, lpmat, sctx->runtime.win_size, sctx->runtime.mval); float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4]; - transpose_m4_m4(tobmat, obmat); + transpose_m4_m4(tobmat, sctx->ret.obmat); for (int i = sctx->runtime.clip_plane_len; i--;) { mul_v4_m4v4(clip_planes_local[i], tobmat, sctx->runtime.clip_plane[i]); } @@ -1931,23 +1772,23 @@ static eSnapMode snap_mesh_polygon(SnapObjectContext *sctx, nearest.dist_sq = square_f(*dist_px); Nearest2dUserData nearest2d; - std::unique_ptr<SnapData_Mesh> *sod_mesh = sctx->mesh_caches.lookup_ptr(ob_eval); - if (sod_mesh) { - nearest2d_data_init_mesh(sod_mesh->get(), + const Mesh *mesh = sctx->ret.data && GS(sctx->ret.data->name) == ID_ME ? + (const Mesh *)sctx->ret.data : + nullptr; + if (mesh) { + nearest2d_data_init_mesh(mesh, sctx->runtime.view_proj == VIEW_PROJ_PERSP, params->use_backface_culling, &nearest2d); - BVHTreeFromMesh *treedata = &sod_mesh->get()->treedata_mesh; - - const MPoly *mp = &sod_mesh->get()->poly[*r_index]; - const MLoop *ml = &treedata->loop[mp->loopstart]; + const MPoly *mp = &mesh->polys()[sctx->ret.index]; + const MLoop *ml = &nearest2d.loop[mp->loopstart]; if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_EDGE) { elem = SCE_SNAP_MODE_EDGE; - BLI_assert(treedata->edge != nullptr); + BLI_assert(nearest2d.edge != nullptr); for (int i = mp->totloop; i--; ml++) { cb_snap_edge(&nearest2d, - ml->e, + (int)ml->e, &neasrest_precalc, clip_planes_local, sctx->runtime.clip_plane_len, @@ -1958,7 +1799,7 @@ static eSnapMode snap_mesh_polygon(SnapObjectContext *sctx, elem = SCE_SNAP_MODE_VERTEX; for (int i = mp->totloop; i--; ml++) { cb_snap_vert(&nearest2d, - ml->v, + (int)ml->v, &neasrest_precalc, clip_planes_local, sctx->runtime.clip_plane_len, @@ -1966,10 +1807,10 @@ static eSnapMode snap_mesh_polygon(SnapObjectContext *sctx, } } } - else { + else if (sctx->ret.is_edit) { /* The object's #BMEditMesh was used to snap instead. */ std::unique_ptr<SnapData_EditMesh> &sod_editmesh = sctx->editmesh_caches.lookup( - BKE_editmesh_from_object(ob_eval)); + BKE_editmesh_from_object(sctx->ret.ob)); BLI_assert(sod_editmesh.get() != nullptr); nearest2d_data_init_editmesh(sod_editmesh.get(), @@ -1980,7 +1821,7 @@ static eSnapMode snap_mesh_polygon(SnapObjectContext *sctx, BMEditMesh *em = sod_editmesh->treedata_editmesh.em; BM_mesh_elem_table_ensure(em->bm, BM_FACE); - BMFace *f = BM_face_at_index(em->bm, *r_index); + BMFace *f = BM_face_at_index(em->bm, sctx->ret.index); BMLoop *l_iter, *l_first; l_iter = l_first = BM_FACE_FIRST_LOOP(f); if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_EDGE) { @@ -2014,19 +1855,19 @@ static eSnapMode snap_mesh_polygon(SnapObjectContext *sctx, if (nearest.index != -1) { *dist_px = sqrtf(nearest.dist_sq); - copy_v3_v3(r_loc, nearest.co); - mul_m4_v3(obmat, r_loc); + copy_v3_v3(sctx->ret.loc, nearest.co); + mul_m4_v3(sctx->ret.obmat, sctx->ret.loc); - if (r_no) { + { float imat[4][4]; - invert_m4_m4(imat, obmat); + invert_m4_m4(imat, sctx->ret.obmat); - copy_v3_v3(r_no, nearest.no); - mul_transposed_mat3_m4_v3(imat, r_no); - normalize_v3(r_no); + copy_v3_v3(sctx->ret.no, nearest.no); + mul_transposed_mat3_m4_v3(imat, sctx->ret.no); + normalize_v3(sctx->ret.no); } - *r_index = nearest.index; + sctx->ret.index = nearest.index; return elem; } @@ -2035,45 +1876,44 @@ static eSnapMode snap_mesh_polygon(SnapObjectContext *sctx, static eSnapMode snap_mesh_edge_verts_mixed(SnapObjectContext *sctx, const SnapObjectParams *params, - Object *ob_eval, - const float obmat[4][4], float original_dist_px, const float prev_co[3], /* read/write args */ - float *dist_px, - /* return args */ - float r_loc[3], - float r_no[3], - int *r_index) + float *dist_px) { eSnapMode elem = SCE_SNAP_MODE_EDGE; - if (ob_eval->type != OB_MESH) { + if (sctx->ret.ob->type != OB_MESH) { return elem; } Nearest2dUserData nearest2d; { - std::unique_ptr<SnapData_Mesh> *sod_mesh = sctx->mesh_caches.lookup_ptr(ob_eval); - if (sod_mesh) { - nearest2d_data_init_mesh(sod_mesh->get(), + const Mesh *mesh = sctx->ret.data && GS(sctx->ret.data->name) == ID_ME ? + (const Mesh *)sctx->ret.data : + nullptr; + if (mesh) { + nearest2d_data_init_mesh(mesh, sctx->runtime.view_proj == VIEW_PROJ_PERSP, params->use_backface_culling, &nearest2d); } - else { + else if (sctx->ret.is_edit) { /* The object's #BMEditMesh was used to snap instead. */ std::unique_ptr<SnapData_EditMesh> &sod_editmesh = sctx->editmesh_caches.lookup( - BKE_editmesh_from_object(ob_eval)); + BKE_editmesh_from_object(sctx->ret.ob)); nearest2d_data_init_editmesh(sod_editmesh.get(), sctx->runtime.view_proj == VIEW_PROJ_PERSP, params->use_backface_culling, &nearest2d); } + else { + return elem; + } } int vindex[2]; - nearest2d.get_edge_verts_index(*r_index, &nearest2d, vindex); + nearest2d.get_edge_verts_index(sctx->ret.index, &nearest2d, vindex); const float *v_pair[2]; nearest2d.get_vert_co(vindex[0], &nearest2d, &v_pair[0]); @@ -2082,7 +1922,7 @@ static eSnapMode snap_mesh_edge_verts_mixed(SnapObjectContext *sctx, DistProjectedAABBPrecalc neasrest_precalc; { float lpmat[4][4]; - mul_m4_m4m4(lpmat, sctx->runtime.pmat, obmat); + mul_m4_m4m4(lpmat, sctx->runtime.pmat, sctx->ret.obmat); dist_squared_to_projected_aabb_precalc( &neasrest_precalc, lpmat, sctx->runtime.win_size, sctx->runtime.mval); @@ -2120,12 +1960,12 @@ static eSnapMode snap_mesh_edge_verts_mixed(SnapObjectContext *sctx, nearest.co)) { nearest.index = vindex[v_id]; elem = SCE_SNAP_MODE_VERTEX; - if (r_no) { + { float imat[4][4]; - invert_m4_m4(imat, obmat); - nearest2d.copy_vert_no(vindex[v_id], &nearest2d, r_no); - mul_transposed_mat3_m4_v3(imat, r_no); - normalize_v3(r_no); + invert_m4_m4(imat, sctx->ret.obmat); + nearest2d.copy_vert_no(vindex[v_id], &nearest2d, sctx->ret.no); + mul_transposed_mat3_m4_v3(imat, sctx->ret.no); + normalize_v3(sctx->ret.no); } } } @@ -2144,7 +1984,7 @@ static eSnapMode snap_mesh_edge_verts_mixed(SnapObjectContext *sctx, vmid, &nearest.dist_sq, nearest.co)) { - nearest.index = *r_index; + nearest.index = sctx->ret.index; elem = SCE_SNAP_MODE_EDGE_MIDPOINT; } } @@ -2153,8 +1993,8 @@ static eSnapMode snap_mesh_edge_verts_mixed(SnapObjectContext *sctx, if (prev_co && (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_EDGE_PERPENDICULAR)) { float v_near[3], va_g[3], vb_g[3]; - mul_v3_m4v3(va_g, obmat, v_pair[0]); - mul_v3_m4v3(vb_g, obmat, v_pair[1]); + mul_v3_m4v3(va_g, sctx->ret.obmat, v_pair[0]); + mul_v3_m4v3(vb_g, sctx->ret.obmat, v_pair[1]); lambda = line_point_factor_v3(prev_co, va_g, vb_g); if (IN_RANGE(lambda, 0.0f, 1.0f)) { @@ -2171,7 +2011,7 @@ static eSnapMode snap_mesh_edge_verts_mixed(SnapObjectContext *sctx, v_near, &nearest.dist_sq, nearest.co)) { - nearest.index = *r_index; + nearest.index = sctx->ret.index; elem = SCE_SNAP_MODE_EDGE_PERPENDICULAR; } } @@ -2182,12 +2022,12 @@ static eSnapMode snap_mesh_edge_verts_mixed(SnapObjectContext *sctx, if (nearest.index != -1) { *dist_px = sqrtf(nearest.dist_sq); - copy_v3_v3(r_loc, nearest.co); + copy_v3_v3(sctx->ret.loc, nearest.co); if (elem != SCE_SNAP_MODE_EDGE_PERPENDICULAR) { - mul_m4_v3(obmat, r_loc); + mul_m4_v3(sctx->ret.obmat, sctx->ret.loc); } - *r_index = nearest.index; + sctx->ret.index = nearest.index; } return elem; @@ -2708,45 +2548,34 @@ static eSnapMode snapMesh(SnapObjectContext *sctx, float dist_px_sq = square_f(*dist_px); /* Test BoundBox */ - const BoundBox *bb = BKE_object_boundbox_get(ob_eval); - if (bb && - !snap_bound_box_check_dist( - bb->vec[0], bb->vec[6], lpmat, sctx->runtime.win_size, sctx->runtime.mval, dist_px_sq)) { - return SCE_SNAP_MODE_NONE; - } - - SnapData_Mesh *sod = snap_object_data_mesh_get(sctx, ob_eval, me_eval, use_hide); - - BVHTreeFromMesh *treedata, treedata_tmp; - treedata = &sod->treedata_mesh; - - if (sod->has_loose_edge && sod->bvhtree[0] == nullptr) { - sod->bvhtree[0] = BKE_bvhtree_from_mesh_get( - &treedata_tmp, me_eval, BVHTREE_FROM_LOOSEEDGES, 2); - if (sod->bvhtree[0] == nullptr) { - sod->has_loose_edge = false; + if (ob_eval->data == me_eval) { + const BoundBox *bb = BKE_object_boundbox_get(ob_eval); + if (!snap_bound_box_check_dist(bb->vec[0], + bb->vec[6], + lpmat, + sctx->runtime.win_size, + sctx->runtime.mval, + dist_px_sq)) { + return SCE_SNAP_MODE_NONE; } - sod->cached[0] = treedata_tmp.cached; } + BVHTreeFromMesh treedata, treedata_dummy; + snap_object_data_mesh_get(sctx, ob_eval, me_eval, use_hide, &treedata); + + BVHTree *bvhtree[2] = {nullptr}; + bvhtree[0] = BKE_bvhtree_from_mesh_get(&treedata_dummy, me_eval, BVHTREE_FROM_LOOSEEDGES, 2); + BLI_assert(treedata_dummy.cached); if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX) { - if (sod->has_loose_vert && sod->bvhtree[1] == nullptr) { - sod->bvhtree[1] = BKE_bvhtree_from_mesh_get( - &treedata_tmp, me_eval, BVHTREE_FROM_LOOSEVERTS, 2); - if (sod->bvhtree[1] == nullptr) { - sod->has_loose_vert = false; - } - sod->cached[1] = treedata_tmp.cached; - } - } - else { - /* Not necessary, just to keep the data more consistent. */ - sod->has_loose_vert = false; + bvhtree[1] = BKE_bvhtree_from_mesh_get(&treedata_dummy, me_eval, BVHTREE_FROM_LOOSEVERTS, 2); + BLI_assert(treedata_dummy.cached); } Nearest2dUserData nearest2d; - nearest2d_data_init_mesh( - sod, sctx->runtime.view_proj == VIEW_PROJ_PERSP, params->use_backface_culling, &nearest2d); + nearest2d_data_init_mesh(me_eval, + sctx->runtime.view_proj == VIEW_PROJ_PERSP, + params->use_backface_culling, + &nearest2d); BVHTreeNearest nearest{}; nearest.index = -1; @@ -2761,9 +2590,10 @@ static eSnapMode snapMesh(SnapObjectContext *sctx, mul_v4_m4v4(clip_planes_local[i], tobmat, sctx->runtime.clip_plane[i]); } - if (sod->bvhtree[1] && (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX)) { + if (bvhtree[1]) { + BLI_assert(sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX); /* snap to loose verts */ - BLI_bvhtree_find_nearest_projected(sod->bvhtree[1], + BLI_bvhtree_find_nearest_projected(bvhtree[1], lpmat, sctx->runtime.win_size, sctx->runtime.mval, @@ -2777,9 +2607,9 @@ static eSnapMode snapMesh(SnapObjectContext *sctx, } if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_EDGE) { - if (sod->bvhtree[0]) { + if (bvhtree[0]) { /* snap to loose edges */ - BLI_bvhtree_find_nearest_projected(sod->bvhtree[0], + BLI_bvhtree_find_nearest_projected(bvhtree[0], lpmat, sctx->runtime.win_size, sctx->runtime.mval, @@ -2790,9 +2620,9 @@ static eSnapMode snapMesh(SnapObjectContext *sctx, &nearest2d); } - if (treedata->tree) { + if (treedata.tree) { /* snap to looptris */ - BLI_bvhtree_find_nearest_projected(treedata->tree, + BLI_bvhtree_find_nearest_projected(treedata.tree, lpmat, sctx->runtime.win_size, sctx->runtime.mval, @@ -2809,9 +2639,9 @@ static eSnapMode snapMesh(SnapObjectContext *sctx, } else { BLI_assert(sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX); - if (sod->bvhtree[0]) { + if (bvhtree[0]) { /* snap to loose edge verts */ - BLI_bvhtree_find_nearest_projected(sod->bvhtree[0], + BLI_bvhtree_find_nearest_projected(bvhtree[0], lpmat, sctx->runtime.win_size, sctx->runtime.mval, @@ -2822,9 +2652,9 @@ static eSnapMode snapMesh(SnapObjectContext *sctx, &nearest2d); } - if (treedata->tree) { + if (treedata.tree) { /* snap to looptri verts */ - BLI_bvhtree_find_nearest_projected(treedata->tree, + BLI_bvhtree_find_nearest_projected(treedata.tree, lpmat, sctx->runtime.win_size, sctx->runtime.mval, @@ -3044,118 +2874,130 @@ static eSnapMode snapEditMesh(SnapObjectContext *sctx, struct SnapObjUserData { /* read/write args */ float *dist_px; - /* return args */ - float *r_loc; - float *r_no; - int *r_index; - Object **r_ob; - float (*r_obmat)[4]; - eSnapMode ret; }; /** * \note Duplicate args here are documented at #snapObjectsRay */ -static void snap_obj_fn(SnapObjectContext *sctx, - const SnapObjectParams *params, - Object *ob_eval, - const float obmat[4][4], - bool is_object_active, - void *data) +static eSnapMode snap_obj_fn(SnapObjectContext *sctx, + const SnapObjectParams *params, + Object *ob_eval, + ID *ob_data, + const float obmat[4][4], + bool is_object_active, + bool use_hide, + void *data) { SnapObjUserData *dt = static_cast<SnapObjUserData *>(data); eSnapMode retval = SCE_SNAP_MODE_NONE; + bool is_edit = false; - switch (ob_eval->type) { - case OB_MESH: { - const eSnapEditType edit_mode_type = params->edit_mode_type; - bool use_hide; - const Mesh *me_eval = mesh_for_snap(ob_eval, edit_mode_type, &use_hide); - if (me_eval == nullptr) { - BMEditMesh *em = BKE_editmesh_from_object(ob_eval); - if (UNLIKELY(!em)) { /* See #mesh_for_snap doc-string. */ - return; - } - BLI_assert_msg(em == BKE_editmesh_from_object(DEG_get_original_object(ob_eval)), - "Make sure there is only one pointer for looptris"); - retval = snapEditMesh( - sctx, params, ob_eval, em, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); - break; - } - if (ob_eval->dt == OB_BOUNDBOX) { - /* Do not snap to objects that are in bounding box display mode */ - return; - } - - retval = snapMesh(sctx, - params, - ob_eval, - me_eval, - obmat, - use_hide, - dt->dist_px, - dt->r_loc, - dt->r_no, - dt->r_index); - break; + if (ob_data == nullptr && (ob_eval->type == OB_MESH)) { + BMEditMesh *em = BKE_editmesh_from_object(ob_eval); + if (UNLIKELY(!em)) { /* See #data_for_snap doc-string. */ + return SCE_SNAP_MODE_NONE; } - case OB_ARMATURE: - retval = snapArmature(sctx, + retval = snapEditMesh(sctx, + params, + ob_eval, + em, + obmat, + dt->dist_px, + sctx->ret.loc, + sctx->ret.no, + &sctx->ret.index); + if (retval) { + is_edit = true; + } + } + else if (ob_data == nullptr) { + retval = snap_object_center( + sctx, ob_eval, obmat, dt->dist_px, sctx->ret.loc, sctx->ret.no, &sctx->ret.index); + } + else { + switch (ob_eval->type) { + case OB_MESH: { + if (ob_eval->dt == OB_BOUNDBOX) { + /* Do not snap to objects that are in bounding box display mode */ + return SCE_SNAP_MODE_NONE; + } + if (GS(ob_data->name) == ID_ME) { + retval = snapMesh(sctx, params, ob_eval, + (const Mesh *)ob_data, obmat, - is_object_active, + use_hide, dt->dist_px, - dt->r_loc, - dt->r_no, - dt->r_index); - break; - case OB_CURVES_LEGACY: - case OB_SURF: - if (ob_eval->type == OB_CURVES_LEGACY || BKE_object_is_in_editmode(ob_eval)) { - retval = snapCurve( - sctx, params, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); - if (params->edit_mode_type != SNAP_GEOM_FINAL) { - break; + sctx->ret.loc, + sctx->ret.no, + &sctx->ret.index); } + break; } - ATTR_FALLTHROUGH; - case OB_FONT: { - const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval); - if (mesh_eval) { - retval |= snapMesh(sctx, - params, - ob_eval, - mesh_eval, - obmat, - false, - dt->dist_px, - dt->r_loc, - dt->r_no, - dt->r_index); + case OB_ARMATURE: + retval = snapArmature(sctx, + params, + ob_eval, + obmat, + is_object_active, + dt->dist_px, + sctx->ret.loc, + sctx->ret.no, + &sctx->ret.index); + break; + case OB_CURVES_LEGACY: + case OB_SURF: + if (ob_eval->type == OB_CURVES_LEGACY || BKE_object_is_in_editmode(ob_eval)) { + retval = snapCurve(sctx, + params, + ob_eval, + obmat, + dt->dist_px, + sctx->ret.loc, + sctx->ret.no, + &sctx->ret.index); + if (params->edit_mode_type != SNAP_GEOM_FINAL) { + break; + } + } + ATTR_FALLTHROUGH; + case OB_FONT: { + const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval); + if (mesh_eval) { + retval |= snapMesh(sctx, + params, + ob_eval, + mesh_eval, + obmat, + false, + dt->dist_px, + sctx->ret.loc, + sctx->ret.no, + &sctx->ret.index); + } + break; } - break; + case OB_EMPTY: + case OB_GPENCIL: + case OB_LAMP: + retval = snap_object_center( + sctx, ob_eval, obmat, dt->dist_px, sctx->ret.loc, sctx->ret.no, &sctx->ret.index); + break; + case OB_CAMERA: + retval = snapCamera( + sctx, ob_eval, obmat, dt->dist_px, sctx->ret.loc, sctx->ret.no, &sctx->ret.index); + break; } - case OB_EMPTY: - case OB_GPENCIL: - case OB_LAMP: - retval = snap_object_center( - sctx, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); - break; - case OB_CAMERA: - retval = snapCamera(sctx, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index); - break; } if (retval) { - if (dt->r_ob) { - *dt->r_ob = ob_eval; - } - if (dt->r_obmat) { - copy_m4_m4(dt->r_obmat, obmat); - } - dt->ret = retval; + copy_m4_m4(sctx->ret.obmat, obmat); + sctx->ret.ob = ob_eval; + sctx->ret.data = ob_data; + sctx->ret.is_edit = is_edit; } + return retval; } /** @@ -3170,42 +3012,18 @@ static void snap_obj_fn(SnapObjectContext *sctx, * --------------- * * \param dist_px: Maximum threshold distance (in pixels). - * - * Output Args - * ----------- - * - * \param r_loc: Hit location. - * \param r_no: Hit normal (optional). - * \param r_index: Hit index or -1 when no valid index is found. - * (currently only set to the polygon index when using `snap_to == SCE_SNAP_MODE_FACE_RAYCAST`). - * \param r_ob: Hit object. - * \param r_obmat: Object matrix (may not be #Object.object_to_world with dupli-instances). */ static eSnapMode snapObjectsRay(SnapObjectContext *sctx, const SnapObjectParams *params, /* read/write args */ /* Parameters below cannot be const, because they are assigned to a * non-const variable (readability-non-const-parameter). */ - float *dist_px /* NOLINT */, - /* return args */ - float r_loc[3] /* NOLINT */, - float r_no[3] /* NOLINT */, - int *r_index /* NOLINT */, - Object **r_ob, - float r_obmat[4][4]) + float *dist_px /* NOLINT */) { SnapObjUserData data = {}; data.dist_px = dist_px; - data.r_loc = r_loc; - data.r_no = r_no; - data.r_ob = r_ob; - data.r_index = r_index; - data.r_obmat = r_obmat; - data.ret = SCE_SNAP_MODE_NONE; - - iter_snap_objects(sctx, params, snap_obj_fn, &data); - return data.ret; + return iter_snap_objects(sctx, params, snap_obj_fn, &data); } /** \} */ @@ -3260,17 +3078,33 @@ bool ED_transform_snap_object_project_ray_ex(SnapObjectContext *sctx, sctx->runtime.depsgraph = depsgraph; sctx->runtime.v3d = v3d; - return raycastObjects(sctx, - params, - ray_start, - ray_normal, - ray_depth, - r_loc, - r_no, - r_index, - r_ob, - r_obmat, - nullptr); + zero_v3(sctx->ret.loc); + zero_v3(sctx->ret.no); + sctx->ret.index = -1; + zero_m4(sctx->ret.obmat); + sctx->ret.hit_list = nullptr; + sctx->ret.ob = nullptr; + sctx->ret.data = nullptr; + sctx->ret.dist_sq = FLT_MAX; + sctx->ret.is_edit = false; + + if (raycastObjects(sctx, params, ray_start, ray_normal, ray_depth)) { + copy_v3_v3(r_loc, sctx->ret.loc); + if (r_no) { + copy_v3_v3(r_no, sctx->ret.no); + } + if (r_index) { + *r_index = sctx->ret.index; + } + if (r_ob) { + *r_ob = sctx->ret.ob; + } + if (r_obmat) { + copy_m4_m4(r_obmat, sctx->ret.obmat); + } + return true; + } + return false; } bool ED_transform_snap_object_project_ray_all(SnapObjectContext *sctx, @@ -3286,6 +3120,16 @@ bool ED_transform_snap_object_project_ray_all(SnapObjectContext *sctx, sctx->runtime.depsgraph = depsgraph; sctx->runtime.v3d = v3d; + zero_v3(sctx->ret.loc); + zero_v3(sctx->ret.no); + sctx->ret.index = -1; + zero_m4(sctx->ret.obmat); + sctx->ret.hit_list = r_hit_list; + sctx->ret.ob = nullptr; + sctx->ret.data = nullptr; + sctx->ret.dist_sq = FLT_MAX; + sctx->ret.is_edit = false; + if (ray_depth == -1.0f) { ray_depth = BVH_RAYCAST_DIST_MAX; } @@ -3294,28 +3138,17 @@ bool ED_transform_snap_object_project_ray_all(SnapObjectContext *sctx, float ray_depth_prev = ray_depth; #endif - bool retval = raycastObjects(sctx, - params, - ray_start, - ray_normal, - &ray_depth, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - r_hit_list); - - /* meant to be readonly for 'all' hits, ensure it is */ + if (raycastObjects(sctx, params, ray_start, ray_normal, &ray_depth)) { + if (sort) { + BLI_listbase_sort(r_hit_list, hit_depth_cmp); + } + /* meant to be readonly for 'all' hits, ensure it is */ #ifdef DEBUG - BLI_assert(ray_depth_prev == ray_depth); + BLI_assert(ray_depth_prev == ray_depth); #endif - - if (sort) { - BLI_listbase_sort(r_hit_list, hit_depth_cmp); + return true; } - - return retval; + return false; } /** @@ -3395,18 +3228,21 @@ static eSnapMode transform_snap_context_project_view3d_mixed_impl(SnapObjectCont sctx->runtime.region = region; sctx->runtime.v3d = v3d; + zero_v3(sctx->ret.loc); + zero_v3(sctx->ret.no); + sctx->ret.index = -1; + zero_m4(sctx->ret.obmat); + sctx->ret.hit_list = nullptr; + sctx->ret.ob = nullptr; + sctx->ret.data = nullptr; + sctx->ret.dist_sq = FLT_MAX; + sctx->ret.is_edit = false; + BLI_assert((snap_to_flag & SCE_SNAP_MODE_GEOM) != 0); eSnapMode retval = SCE_SNAP_MODE_NONE; bool has_hit = false; - Object *ob_eval = nullptr; - float loc[3]; - /* Not all snapping callbacks set the normal, - * initialize this since any hit copies both the `loc` and `no`. */ - float no[3] = {0.0f, 0.0f, 0.0f}; - float obmat[4][4]; - int index = -1; const RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata); @@ -3415,24 +3251,23 @@ static eSnapMode transform_snap_context_project_view3d_mixed_impl(SnapObjectCont /* NOTE: if both face ray-cast and face nearest are enabled, first find result of nearest, then * override with ray-cast. */ if ((snap_to_flag & SCE_SNAP_MODE_FACE_NEAREST) && !has_hit) { - has_hit = nearestWorldObjects( - sctx, params, init_co, prev_co, loc, no, &index, &ob_eval, obmat); + has_hit = nearestWorldObjects(sctx, params, init_co, prev_co); if (has_hit) { retval = SCE_SNAP_MODE_FACE_NEAREST; - copy_v3_v3(r_loc, loc); + copy_v3_v3(r_loc, sctx->ret.loc); if (r_no) { - copy_v3_v3(r_no, no); + copy_v3_v3(r_no, sctx->ret.no); } if (r_ob) { - *r_ob = ob_eval; + *r_ob = sctx->ret.ob; } if (r_obmat) { - copy_m4_m4(r_obmat, obmat); + copy_m4_m4(r_obmat, sctx->ret.obmat); } if (r_index) { - *r_index = index; + *r_index = sctx->ret.index; } } } @@ -3446,38 +3281,28 @@ static eSnapMode transform_snap_context_project_view3d_mixed_impl(SnapObjectCont float dummy_ray_depth = BVH_RAYCAST_DIST_MAX; - has_hit = raycastObjects(sctx, - params, - ray_start, - ray_normal, - &dummy_ray_depth, - loc, - no, - &index, - &ob_eval, - obmat, - nullptr); + has_hit = raycastObjects(sctx, params, ray_start, ray_normal, &dummy_ray_depth); if (has_hit) { if (r_face_nor) { - copy_v3_v3(r_face_nor, no); + copy_v3_v3(r_face_nor, sctx->ret.no); } if (snap_to_flag & SCE_SNAP_MODE_FACE_RAYCAST) { retval = SCE_SNAP_MODE_FACE_RAYCAST; - copy_v3_v3(r_loc, loc); + copy_v3_v3(r_loc, sctx->ret.loc); if (r_no) { - copy_v3_v3(r_no, no); + copy_v3_v3(r_no, sctx->ret.no); } if (r_ob) { - *r_ob = ob_eval; + *r_ob = sctx->ret.ob; } if (r_obmat) { - copy_m4_m4(r_obmat, obmat); + copy_m4_m4(r_obmat, sctx->ret.obmat); } if (r_index) { - *r_index = index; + *r_index = sctx->ret.index; } } } @@ -3514,11 +3339,11 @@ static eSnapMode transform_snap_context_project_view3d_mixed_impl(SnapObjectCont sctx->runtime.has_occlusion_plane = false; /* By convention we only snap to the original elements of a curve. */ - if (has_hit && ob_eval->type != OB_CURVES_LEGACY) { + if (has_hit && sctx->ret.ob->type != OB_CURVES_LEGACY) { /* Compute the new clip_pane but do not add it yet. */ float new_clipplane[4]; - BLI_ASSERT_UNIT_V3(no); - plane_from_point_normal_v3(new_clipplane, loc, no); + BLI_ASSERT_UNIT_V3(sctx->ret.no); + plane_from_point_normal_v3(new_clipplane, sctx->ret.loc, sctx->ret.no); if (dot_v3v3(sctx->runtime.clip_plane[0], new_clipplane) > 0.0f) { /* The plane is facing the wrong direction. */ negate_v4(new_clipplane); @@ -3528,7 +3353,7 @@ static eSnapMode transform_snap_context_project_view3d_mixed_impl(SnapObjectCont new_clipplane[3] += 0.01f; /* Try to snap only to the polygon. */ - elem_test = snap_mesh_polygon(sctx, params, ob_eval, obmat, &dist_px_tmp, loc, no, &index); + elem_test = snap_mesh_polygon(sctx, params, &dist_px_tmp); if (elem_test) { elem = elem_test; } @@ -3542,7 +3367,7 @@ static eSnapMode transform_snap_context_project_view3d_mixed_impl(SnapObjectCont sctx->runtime.has_occlusion_plane = true; } - elem_test = snapObjectsRay(sctx, params, &dist_px_tmp, loc, no, &index, &ob_eval, obmat); + elem_test = snapObjectsRay(sctx, params, &dist_px_tmp); if (elem_test) { elem = elem_test; } @@ -3551,25 +3376,24 @@ static eSnapMode transform_snap_context_project_view3d_mixed_impl(SnapObjectCont (snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR))) { sctx->runtime.snap_to_flag = snap_to_flag; - elem = snap_mesh_edge_verts_mixed( - sctx, params, ob_eval, obmat, *dist_px, prev_co, &dist_px_tmp, loc, no, &index); + elem = snap_mesh_edge_verts_mixed(sctx, params, *dist_px, prev_co, &dist_px_tmp); } if (elem & snap_to_flag) { retval = elem; - copy_v3_v3(r_loc, loc); + copy_v3_v3(r_loc, sctx->ret.loc); if (r_no) { - copy_v3_v3(r_no, no); + copy_v3_v3(r_no, sctx->ret.no); } if (r_ob) { - *r_ob = ob_eval; + *r_ob = sctx->ret.ob; } if (r_obmat) { - copy_m4_m4(r_obmat, obmat); + copy_m4_m4(r_obmat, sctx->ret.obmat); } if (r_index) { - *r_index = index; + *r_index = sctx->ret.index; } *dist_px = dist_px_tmp; diff --git a/source/blender/editors/uvedit/uvedit_islands.cc b/source/blender/editors/uvedit/uvedit_islands.cc index 92745667505..d8e10435146 100644 --- a/source/blender/editors/uvedit/uvedit_islands.cc +++ b/source/blender/editors/uvedit/uvedit_islands.cc @@ -36,29 +36,48 @@ #include "bmesh.h" -/* -------------------------------------------------------------------- */ -/** \name UV Face Utilities - * \{ */ +static void mul_v2_m2_add_v2v2(float r[2], + const float mat[2][2], + const float a[2], + const float b[2]) +{ + /* Compute `r = mat * (a + b)` with high precision. */ + const double x = static_cast<double>(a[0]) + static_cast<double>(b[0]); + const double y = static_cast<double>(a[1]) + static_cast<double>(b[1]); + + r[0] = static_cast<float>(mat[0][0] * x + mat[1][0] * y); + r[1] = static_cast<float>(mat[0][1] * x + mat[1][1] * y); +} -static void bm_face_uv_translate_and_scale_around_pivot(BMFace *f, - const float offset[2], - const float scale[2], - const float pivot[2], - const int cd_loop_uv_offset) +static void island_uv_transform(FaceIsland *island, + const float matrix[2][2], /* Scale and rotation. */ + const float pre_translate[2] /* (pre) Translation. */ +) { - BMLoop *l_iter; - BMLoop *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - MLoopUV *luv = static_cast<MLoopUV *>(BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset)); - for (int i = 0; i < 2; i++) { - luv->uv[i] = offset[i] + (((luv->uv[i] - pivot[i]) * scale[i]) + pivot[i]); + /* Use a pre-transform to compute `A * (x+b)` + * + * \note Ordinarily, we'd use a post_transform like `A * x + b` + * In general, post-transforms are easier to work with when using homogenous co-ordinates. + * + * When UV mapping into the unit square, post-transforms can lose precision on small islands. + * Instead we're using a pre-transform to maintain precision. + * + * To convert post-transform to pre-transform, use `A * x + b == A * (x + c), c = A^-1 * b` + */ + + const int cd_loop_uv_offset = island->cd_loop_uv_offset; + const int faces_len = island->faces_len; + for (int i = 0; i < faces_len; i++) { + BMFace *f = island->faces[i]; + BMLoop *l; + BMIter iter; + BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) { + MLoopUV *luv = (MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + mul_v2_m2_add_v2v2(luv->uv, matrix, luv->uv, pre_translate); } - } while ((l_iter = l_iter->next) != l_first); + } } -/** \} */ - /* -------------------------------------------------------------------- */ /** \name UV Face Array Utilities * \{ */ @@ -198,13 +217,12 @@ static void face_island_uv_rotate_fit_aabb(FaceIsland *island) /* Apply rotation back to BMesh. */ if (angle != 0.0f) { float matrix[2][2]; + float pre_translate[2] = {0, 0}; angle_to_mat2(matrix, angle); matrix[1][0] *= 1.0f / aspect_y; /* matrix[1][1] *= aspect_y / aspect_y; */ matrix[0][1] *= aspect_y; - for (int i = 0; i < faces_len; i++) { - BM_face_uv_transform(faces[i], matrix, cd_loop_uv_offset); - } + island_uv_transform(island, matrix, pre_translate); } } @@ -769,21 +787,24 @@ void ED_uvedit_pack_islands_multi(const Scene *scene, } } + float matrix[2][2]; + float matrix_inverse[2][2]; + float pre_translate[2]; for (int i = 0; i < island_vector.size(); i++) { FaceIsland *island = island_vector[box_array[i].index]; - const float pivot[2] = { - island->bounds_rect.xmin, - island->bounds_rect.ymin, - }; - const float offset[2] = { - ((box_array[i].x * scale[0]) - island->bounds_rect.xmin) + base_offset[0], - ((box_array[i].y * scale[1]) - island->bounds_rect.ymin) + base_offset[1], - }; - for (int j = 0; j < island->faces_len; j++) { - BMFace *efa = island->faces[j]; - bm_face_uv_translate_and_scale_around_pivot( - efa, offset, scale, pivot, island->cd_loop_uv_offset); - } + matrix[0][0] = scale[0]; + matrix[0][1] = 0.0f; + matrix[1][0] = 0.0f; + matrix[1][1] = scale[1]; + invert_m2_m2(matrix_inverse, matrix); + + /* Add base_offset, post transform. */ + mul_v2_m2v2(pre_translate, matrix_inverse, base_offset); + + /* Translate to box_array from bounds_rect. */ + pre_translate[0] += box_array[i].x - island->bounds_rect.xmin; + pre_translate[1] += box_array[i].y - island->bounds_rect.ymin; + island_uv_transform(island, matrix, pre_translate); } for (uint ob_index = 0; ob_index < objects_len; ob_index++) { diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index b65f4889347..0e77a8ba4ad 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -111,8 +111,8 @@ bool ED_object_get_active_image(Object *ob, int mat_nr, Image **r_ima, ImageUser **r_iuser, - bNode **r_node, - bNodeTree **r_ntree) + const bNode **r_node, + const bNodeTree **r_ntree) { Material *ma = DEG_is_evaluated_object(ob) ? BKE_object_material_get_eval(ob, mat_nr) : BKE_object_material_get(ob, mat_nr); |