diff options
author | Hans Goudey <h.goudey@me.com> | 2022-01-22 02:22:11 +0300 |
---|---|---|
committer | Hans Goudey <h.goudey@me.com> | 2022-01-22 02:22:11 +0300 |
commit | 32832197adc1550b63d9ff90d0eaa76f8c136e46 (patch) | |
tree | 40c26cc538167df3e01841933c4e76b149c110b0 | |
parent | 02d167277d7cf1f5f558cfde51c05258b352b328 (diff) | |
parent | 45d038181ae25972011f9656ba4f7062aa1c534f (diff) |
Merge branch 'master' into temp-geometry-nodes-extrude-mesh
15 files changed, 132 insertions, 190 deletions
diff --git a/build_files/cmake/platform/platform_apple.cmake b/build_files/cmake/platform/platform_apple.cmake index 447645b6806..8acea1be841 100644 --- a/build_files/cmake/platform/platform_apple.cmake +++ b/build_files/cmake/platform/platform_apple.cmake @@ -166,7 +166,11 @@ if(WITH_FFTW3) find_package(Fftw3) endif() +# FreeType compiled with Brotli compression for woff2. find_package(Freetype REQUIRED) +list(APPEND FREETYPE_LIBRARIES + ${LIBDIR}/brotli/lib/libbrotlicommon-static.a + ${LIBDIR}/brotli/lib/libbrotlidec-static.a) if(WITH_IMAGE_OPENEXR) find_package(OpenEXR) diff --git a/source/blender/blenkernel/intern/curve.cc b/source/blender/blenkernel/intern/curve.cc index 755b05e2697..70edaccb244 100644 --- a/source/blender/blenkernel/intern/curve.cc +++ b/source/blender/blenkernel/intern/curve.cc @@ -30,6 +30,7 @@ #include "BLI_blenlib.h" #include "BLI_endian_switch.h" #include "BLI_ghash.h" +#include "BLI_index_range.hh" #include "BLI_math.h" #include "BLI_utildefines.h" @@ -67,10 +68,12 @@ #include "BLO_read_write.h" +using blender::IndexRange; + /* globals */ /* local */ -static CLG_LogRef LOG = {"bke.curve"}; +// static CLG_LogRef LOG = {"bke.curve"}; static void curve_init_data(ID *id) { @@ -1160,81 +1163,34 @@ void BKE_nurb_bpoint_calc_plane(struct Nurb *nu, BPoint *bp, float r_plane[3]) static void calcknots(float *knots, const int pnts, const short order, const short flag) { - /* knots: number of pnts NOT corrected for cyclic */ - const int pnts_order = pnts + order; - float k; - int a; + const bool is_cyclic = flag & CU_NURB_CYCLIC; + const bool is_bezier = flag & CU_NURB_BEZIER && !(flag & CU_NURB_ENDPOINT); + const bool is_end_point = flag & CU_NURB_ENDPOINT && !(flag & CU_NURB_BEZIER); + /* Inner knots are always repeated once except on Bezier case. */ + const int repeat_inner = is_bezier ? order - 1 : 1; + /* How many times to repeat 0.0 at the beginning of knot. */ + const int head = is_end_point && !is_cyclic ? order : (is_bezier ? order / 2 : 1); + /* Number of knots replicating widths of the starting knots. + * Covers both Cyclic and EndPoint cases. */ + const int tail = is_cyclic ? 2 * order - 1 : (is_end_point ? order : 0); - switch (flag & (CU_NURB_ENDPOINT | CU_NURB_BEZIER)) { - case CU_NURB_ENDPOINT: - k = 0.0; - for (a = 1; a <= pnts_order; a++) { - knots[a - 1] = k; - if (a >= order && a <= pnts) { - k += 1.0f; - } - } - break; - case CU_NURB_BEZIER: - /* Warning, the order MUST be 2 or 4, - * if this is not enforced, the displist will be corrupt */ - if (order == 4) { - k = 0.34; - for (a = 0; a < pnts_order; a++) { - knots[a] = floorf(k); - k += (1.0f / 3.0f); - } - } - else if (order == 3) { - k = 0.6f; - for (a = 0; a < pnts_order; a++) { - if (a >= order && a <= pnts) { - k += 0.5f; - } - knots[a] = floorf(k); - } - } - else { - CLOG_ERROR(&LOG, "bez nurb curve order is not 3 or 4, should never happen"); - } - break; - default: - for (a = 0; a < pnts_order; a++) { - knots[a] = (float)a; - } - break; - } -} - -static void makecyclicknots(float *knots, int pnts, short order) -/* pnts, order: number of pnts NOT corrected for cyclic */ -{ - int a, b, order2, c; - - if (knots == nullptr) { - return; - } + const int knot_count = pnts + order + (is_cyclic ? order - 1 : 0); - order2 = order - 1; + int r = head; + float current = 0.0f; - /* do first long rows (order -1), remove identical knots at endpoints */ - if (order > 2) { - b = pnts + order2; - for (a = 1; a < order2; a++) { - if (knots[b] != knots[b - a]) { - break; - } - } - if (a == order2) { - knots[pnts + order - 2] += 1.0f; + for (const int i : IndexRange(knot_count - tail)) { + knots[i] = current; + r--; + if (r == 0) { + current += 1.0; + r = repeat_inner; } } - b = order; - c = pnts + order + order2; - for (a = pnts + order2; a < c; a++) { - knots[a] = knots[a - 1] + (knots[b] - knots[b - 1]); - b--; + const int tail_index = knot_count - tail; + for (const int i : IndexRange(tail)) { + knots[tail_index + i] = current + (knots[i] - knots[0]); } } @@ -1247,13 +1203,7 @@ static void makeknots(Nurb *nu, short uv) } if (BKE_nurb_check_valid_u(nu)) { nu->knotsu = (float *)MEM_calloc_arrayN(KNOTSU(nu) + 1, sizeof(float), "makeknots"); - if (nu->flagu & CU_NURB_CYCLIC) { - calcknots(nu->knotsu, nu->pntsu, nu->orderu, 0); /* cyclic should be uniform */ - makecyclicknots(nu->knotsu, nu->pntsu, nu->orderu); - } - else { - calcknots(nu->knotsu, nu->pntsu, nu->orderu, nu->flagu); - } + calcknots(nu->knotsu, nu->pntsu, nu->orderu, nu->flagu); } else { nu->knotsu = nullptr; @@ -1265,13 +1215,7 @@ static void makeknots(Nurb *nu, short uv) } if (BKE_nurb_check_valid_v(nu)) { nu->knotsv = (float *)MEM_calloc_arrayN(KNOTSV(nu) + 1, sizeof(float), "makeknots"); - if (nu->flagv & CU_NURB_CYCLIC) { - calcknots(nu->knotsv, nu->pntsv, nu->orderv, 0); /* cyclic should be uniform */ - makecyclicknots(nu->knotsv, nu->pntsv, nu->orderv); - } - else { - calcknots(nu->knotsv, nu->pntsv, nu->orderv, nu->flagv); - } + calcknots(nu->knotsv, nu->pntsv, nu->orderv, nu->flagv); } else { nu->knotsv = nullptr; diff --git a/source/blender/blenkernel/intern/idprop_serialize.cc b/source/blender/blenkernel/intern/idprop_serialize.cc index 92dce49500c..08a7f13b806 100644 --- a/source/blender/blenkernel/intern/idprop_serialize.cc +++ b/source/blender/blenkernel/intern/idprop_serialize.cc @@ -304,7 +304,7 @@ class IDPStringSerializer : public IDPropertySerializer { std::unique_ptr<IDProperty, IDPropertyDeleter> entry_to_idprop( DictionaryEntryParser &entry_reader) const override { - BLI_assert(entry_reader.get_type().value() == IDP_STRING); + BLI_assert(*(entry_reader.get_type()) == IDP_STRING); std::optional<std::string> name = entry_reader.get_name(); if (!name.has_value()) { return nullptr; @@ -344,7 +344,7 @@ class IDPIntSerializer : public IDPropertySerializer { std::unique_ptr<IDProperty, IDPropertyDeleter> entry_to_idprop( DictionaryEntryParser &entry_reader) const override { - BLI_assert(entry_reader.get_type().value() == IDP_INT); + BLI_assert(*(entry_reader.get_type()) == IDP_INT); std::optional<std::string> name = entry_reader.get_name(); if (!name.has_value()) { return nullptr; @@ -384,7 +384,7 @@ class IDPFloatSerializer : public IDPropertySerializer { std::unique_ptr<IDProperty, IDPropertyDeleter> entry_to_idprop( DictionaryEntryParser &entry_reader) const override { - BLI_assert(entry_reader.get_type().value() == IDP_FLOAT); + BLI_assert(*(entry_reader.get_type()) == IDP_FLOAT); std::optional<std::string> name = entry_reader.get_name(); if (!name.has_value()) { return nullptr; @@ -424,7 +424,7 @@ class IDPDoubleSerializer : public IDPropertySerializer { std::unique_ptr<IDProperty, IDPropertyDeleter> entry_to_idprop( DictionaryEntryParser &entry_reader) const override { - BLI_assert(entry_reader.get_type().value() == IDP_DOUBLE); + BLI_assert(*(entry_reader.get_type()) == IDP_DOUBLE); std::optional<std::string> name = entry_reader.get_name(); if (!name.has_value()) { return nullptr; @@ -502,7 +502,7 @@ class IDPArraySerializer : public IDPropertySerializer { std::unique_ptr<IDProperty, IDPropertyDeleter> entry_to_idprop( DictionaryEntryParser &entry_reader) const override { - BLI_assert(entry_reader.get_type().value() == IDP_ARRAY); + BLI_assert(*(entry_reader.get_type()) == IDP_ARRAY); std::optional<eIDPropertyType> property_subtype = entry_reader.get_subtype(); if (!property_subtype.has_value()) { return nullptr; @@ -556,8 +556,8 @@ class IDPArraySerializer : public IDPropertySerializer { std::unique_ptr<IDProperty, IDPropertyDeleter> idprop_array_int_from_value( DictionaryEntryParser &entry_reader) const { - BLI_assert(entry_reader.get_type().value() == IDP_ARRAY); - BLI_assert(entry_reader.get_subtype().value() == IDP_INT); + BLI_assert(*(entry_reader.get_type()) == IDP_ARRAY); + BLI_assert(*(entry_reader.get_subtype()) == IDP_INT); std::optional<std::string> name = entry_reader.get_name(); if (!name.has_value()) { return nullptr; @@ -572,8 +572,8 @@ class IDPArraySerializer : public IDPropertySerializer { std::unique_ptr<IDProperty, IDPropertyDeleter> idprop_array_float_from_value( DictionaryEntryParser &entry_reader) const { - BLI_assert(entry_reader.get_type().value() == IDP_ARRAY); - BLI_assert(entry_reader.get_subtype().value() == IDP_FLOAT); + BLI_assert(*(entry_reader.get_type()) == IDP_ARRAY); + BLI_assert(*(entry_reader.get_subtype()) == IDP_FLOAT); std::optional<std::string> name = entry_reader.get_name(); if (!name.has_value()) { return nullptr; @@ -588,8 +588,8 @@ class IDPArraySerializer : public IDPropertySerializer { std::unique_ptr<IDProperty, IDPropertyDeleter> idprop_array_double_from_value( DictionaryEntryParser &entry_reader) const { - BLI_assert(entry_reader.get_type().value() == IDP_ARRAY); - BLI_assert(entry_reader.get_subtype().value() == IDP_DOUBLE); + BLI_assert(*(entry_reader.get_type()) == IDP_ARRAY); + BLI_assert(*(entry_reader.get_subtype()) == IDP_DOUBLE); std::optional<std::string> name = entry_reader.get_name(); if (!name.has_value()) { return nullptr; @@ -639,7 +639,7 @@ class IDPGroupSerializer : public IDPropertySerializer { std::unique_ptr<IDProperty, IDPropertyDeleter> entry_to_idprop( DictionaryEntryParser &entry_reader) const override { - BLI_assert(entry_reader.get_type().value() == IDP_GROUP); + BLI_assert(*(entry_reader.get_type()) == IDP_GROUP); std::optional<std::string> name = entry_reader.get_name(); if (!name.has_value()) { return nullptr; @@ -796,7 +796,7 @@ static IDProperty *idprop_from_value(const DictionaryValue &value) return nullptr; } - const IDPropertySerializer &serializer = serializer_for(property_type.value()); + const IDPropertySerializer &serializer = serializer_for(*property_type); return serializer.entry_to_idprop(entry_reader).release(); } diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 72210eea71d..407375c4d22 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -1648,6 +1648,7 @@ static void sculpt_update_object(Depsgraph *depsgraph, ss->totvert = me->totvert; ss->totpoly = me->totpoly; ss->totfaces = me->totpoly; + ss->vert_normals = BKE_mesh_vertex_normals_ensure(me); ss->mvert = me->mvert; ss->mpoly = me->mpoly; ss->mloop = me->mloop; diff --git a/source/blender/blenkernel/intern/spline_nurbs.cc b/source/blender/blenkernel/intern/spline_nurbs.cc index 719ba4b7ecd..5993b9a9a27 100644 --- a/source/blender/blenkernel/intern/spline_nurbs.cc +++ b/source/blender/blenkernel/intern/spline_nurbs.cc @@ -179,65 +179,35 @@ int NURBSpline::knots_size() const void NURBSpline::calculate_knots() const { const KnotsMode mode = this->knots_mode; - const int length = this->size(); const int order = order_; + const bool is_bezier = mode == NURBSpline::KnotsMode::Bezier; + const bool is_end_point = mode == NURBSpline::KnotsMode::EndPoint; + /* Inner knots are always repeated once except on Bezier case. */ + const int repeat_inner = is_bezier ? order - 1 : 1; + /* How many times to repeat 0.0 at the beginning of knot. */ + const int head = is_end_point && !is_cyclic_ ? order : (is_bezier ? order / 2 : 1); + /* Number of knots replicating widths of the starting knots. + * Covers both Cyclic and EndPoint cases. */ + const int tail = is_cyclic_ ? 2 * order - 1 : (is_end_point ? order : 0); knots_.resize(this->knots_size()); - MutableSpan<float> knots = knots_; - if (mode == NURBSpline::KnotsMode::Normal || is_cyclic_) { - for (const int i : knots.index_range()) { - knots[i] = static_cast<float>(i); - } - } - else if (mode == NURBSpline::KnotsMode::EndPoint) { - float k = 0.0f; - for (const int i : IndexRange(1, knots.size())) { - knots[i - 1] = k; - if (i >= order && i <= length) { - k += 1.0f; - } - } - } - else if (mode == NURBSpline::KnotsMode::Bezier) { - BLI_assert(ELEM(order, 3, 4)); - if (order == 3) { - float k = 0.6f; - for (const int i : knots.index_range()) { - if (i >= order && i <= length) { - k += 0.5f; - } - knots[i] = std::floor(k); - } - } - else { - float k = 0.34f; - for (const int i : knots.index_range()) { - knots[i] = std::floor(k); - k += 1.0f / 3.0f; - } - } - } + int r = head; + float current = 0.0f; - if (is_cyclic_) { - const int b = length + order - 1; - if (order > 2) { - for (const int i : IndexRange(1, order - 2)) { - if (knots[b] != knots[b - i]) { - if (i == order - 1) { - knots[length + order - 2] += 1.0f; - break; - } - } - } + for (const int i : IndexRange(knots.size() - tail)) { + knots[i] = current; + r--; + if (r == 0) { + current += 1.0; + r = repeat_inner; } + } - int c = order; - for (int i = b; i < this->knots_size(); i++) { - knots[i] = knots[i - 1] + (knots[c] - knots[c - 1]); - c--; - } + const int tail_index = knots.size() - tail; + for (const int i : IndexRange(tail)) { + knots[tail_index + i] = current + (knots[i] - knots[0]); } } diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index a034e4bb10e..a70bc1c0350 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -4953,19 +4953,22 @@ bool ed_editnurb_spin( if ((a & 1) == 0) { rotateflagNurb(editnurb, SELECT, cent, scalemat1); - weightflagNurb(editnurb, SELECT, 0.25 * M_SQRT2); + weightflagNurb(editnurb, SELECT, 0.5 * M_SQRT2); } else { rotateflagNurb(editnurb, SELECT, cent, scalemat2); - weightflagNurb(editnurb, SELECT, 4.0 / M_SQRT2); + weightflagNurb(editnurb, SELECT, 2.0 / M_SQRT2); } } if (ok) { LISTBASE_FOREACH (Nurb *, nu, editnurb) { if (ED_curve_nurb_select_check(v3d, nu)) { - nu->orderv = 4; - nu->flagv |= CU_NURB_CYCLIC; + nu->orderv = 3; + /* It is challenging to create a good approximation of a circle with uniform knots vector + * (which is forced in Blender for cyclic NURBS curves). Here a NURBS circle is constructed + * by connecting four Bezier arcs. */ + nu->flagv |= CU_NURB_CYCLIC | CU_NURB_BEZIER; BKE_nurb_knot_calc_v(nu); } } diff --git a/source/blender/editors/curve/editcurve_add.c b/source/blender/editors/curve/editcurve_add.c index 614805a70f5..daef4a21692 100644 --- a/source/blender/editors/curve/editcurve_add.c +++ b/source/blender/editors/curve/editcurve_add.c @@ -306,9 +306,9 @@ Nurb *ED_curve_add_nurbs_primitive( else if (cutype == CU_NURBS) { /* nurb */ nu->pntsu = 8; nu->pntsv = 1; - nu->orderu = 4; + nu->orderu = 3; nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * nu->pntsu, "addNurbprim6"); - nu->flagu = CU_NURB_CYCLIC; + nu->flagu = CU_NURB_CYCLIC | CU_NURB_BEZIER; bp = nu->bp; for (a = 0; a < 8; a++) { @@ -322,7 +322,7 @@ Nurb *ED_curve_add_nurbs_primitive( bp->vec[2] += 0.25f * nurbcircle[a][1] * grid; } if (a & 1) { - bp->vec[3] = 0.25 * M_SQRT2; + bp->vec[3] = 0.5 * M_SQRT2; } else { bp->vec[3] = 1.0; diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c index 46a056f865b..5d573271ea3 100644 --- a/source/blender/editors/mesh/editmesh_undo.c +++ b/source/blender/editors/mesh/editmesh_undo.c @@ -687,11 +687,15 @@ static void undomesh_to_editmesh(UndoMesh *um, Object *ob, BMEditMesh *em, Key * .active_shapekey = um->shapenr, })); + /* Normals should not be stored in the undo mesh, so recalculate them. The edit + * mesh is expected to have valid normals and there is no tracked dirty state. */ + BLI_assert(BKE_mesh_vertex_normals_are_dirty(&um->me)); + BM_mesh_normals_update(bm); + em_tmp = BKE_editmesh_create(bm); *em = *em_tmp; - /* Calculate face normals and tessellation at once since it's multi-threaded. - * The vertex normals are stored in the undo-mesh, so this doesn't need to be updated. */ + /* Calculate face normals and tessellation at once since it's multi-threaded. */ BKE_editmesh_looptri_calc_ex(em, &(const struct BMeshCalcTessellation_Params){ .face_normals = true, diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index c320313643d..6d04bd3f9d5 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -811,8 +811,8 @@ static int apply_objects_internal(bContext *C, /* adjust data */ BKE_mesh_transform(me, mat, true); - /* update normals */ - BKE_mesh_calc_normals(me); + /* If normal layers exist, they are now dirty. */ + BKE_mesh_normals_tag_dirty(me); } else if (ob->type == OB_ARMATURE) { bArmature *arm = ob->data; diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc index d6e1d8a7ea5..b77b5735784 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc @@ -17,6 +17,8 @@ /** \file * \ingroup obj */ +/* Silence warnings from copying deprecated fields. Needed for an Object copy constructor use. */ +#define DNA_DEPRECATED_ALLOW #include "BKE_customdata.h" #include "BKE_deform.h" @@ -42,20 +44,21 @@ namespace blender::io::obj { OBJMesh::OBJMesh(Depsgraph *depsgraph, const OBJExportParams &export_params, Object *mesh_object) { - export_object_eval_ = DEG_get_evaluated_object(depsgraph, mesh_object); - export_mesh_eval_ = BKE_object_get_evaluated_mesh(export_object_eval_); + /* We need to copy the object because it may be in temporary space. */ + Object *obj_eval = DEG_get_evaluated_object(depsgraph, mesh_object); + export_object_eval_ = *obj_eval; + export_mesh_eval_ = BKE_object_get_evaluated_mesh(&export_object_eval_); mesh_eval_needs_free_ = false; if (!export_mesh_eval_) { /* Curves and NURBS surfaces need a new mesh when they're * exported in the form of vertices and edges. */ - export_mesh_eval_ = BKE_mesh_new_from_object(depsgraph, export_object_eval_, true, true); + export_mesh_eval_ = BKE_mesh_new_from_object(depsgraph, &export_object_eval_, true, true); /* Since a new mesh been allocated, it needs to be freed in the destructor. */ mesh_eval_needs_free_ = true; } - if (export_params.export_triangulated_mesh && - ELEM(export_object_eval_->type, OB_MESH, OB_SURF)) { + if (export_params.export_triangulated_mesh && ELEM(export_object_eval_.type, OB_MESH, OB_SURF)) { std::tie(export_mesh_eval_, mesh_eval_needs_free_) = triangulate_mesh_eval(); } set_world_axes_transform(export_params.forward_axis, export_params.up_axis); @@ -116,10 +119,10 @@ void OBJMesh::set_world_axes_transform(const eTransformAxisForward forward, mat3_from_axis_conversion(OBJ_AXIS_Y_FORWARD, OBJ_AXIS_Z_UP, forward, up, axes_transform); /* mat3_from_axis_conversion returns a transposed matrix! */ transpose_m3(axes_transform); - mul_m4_m3m4(world_and_axes_transform_, axes_transform, export_object_eval_->obmat); + mul_m4_m3m4(world_and_axes_transform_, axes_transform, export_object_eval_.obmat); /* mul_m4_m3m4 does not transform last row of obmat, i.e. location data. */ - mul_v3_m3v3(world_and_axes_transform_[3], axes_transform, export_object_eval_->obmat[3]); - world_and_axes_transform_[3][3] = export_object_eval_->obmat[3][3]; + mul_v3_m3v3(world_and_axes_transform_[3], axes_transform, export_object_eval_.obmat[3]); + world_and_axes_transform_[3][3] = export_object_eval_.obmat[3][3]; } int OBJMesh::tot_vertices() const @@ -185,8 +188,14 @@ void OBJMesh::calc_smooth_groups(const bool use_bitflags) const Material *OBJMesh::get_object_material(const int16_t mat_nr) const { - /* "+ 1" as material getter needs one-based indices. */ - const Material *r_mat = BKE_object_material_get(export_object_eval_, mat_nr + 1); + /** + * The const_cast is safe here because BKE_object_material_get won't change the object + * but it is a big can of worms to fix the declaration of that function right now. + * + * The call uses "+ 1" as material getter needs one-based indices. + */ + Object *obj = const_cast<Object *>(&export_object_eval_); + const Material *r_mat = BKE_object_material_get(obj, mat_nr + 1); #ifdef DEBUG if (!r_mat) { std::cerr << "Material not found for mat_nr = " << mat_nr << std::endl; @@ -209,7 +218,7 @@ int16_t OBJMesh::ith_poly_matnr(const int poly_index) const const char *OBJMesh::get_object_name() const { - return export_object_eval_->id.name + 2; + return export_object_eval_.id.name + 2; } const char *OBJMesh::get_object_mesh_name() const @@ -403,7 +412,7 @@ int16_t OBJMesh::get_poly_deform_group_index(const int poly_index) const BLI_assert(poly_index < export_mesh_eval_->totpoly); const MPoly &mpoly = export_mesh_eval_->mpoly[poly_index]; const MLoop *mloop = &export_mesh_eval_->mloop[mpoly.loopstart]; - const Object *obj = export_object_eval_; + const Object *obj = &export_object_eval_; const int tot_deform_groups = BKE_object_defgroup_count(obj); /* Indices of the vector index into deform groups of an object; values are the] * number of vertex members in one deform group. */ @@ -444,7 +453,7 @@ int16_t OBJMesh::get_poly_deform_group_index(const int poly_index) const const char *OBJMesh::get_poly_deform_group_name(const int16_t def_group_index) const { const bDeformGroup &vertex_group = *(static_cast<bDeformGroup *>( - BLI_findlink(BKE_object_defgroup_list(export_object_eval_), def_group_index))); + BLI_findlink(BKE_object_defgroup_list(&export_object_eval_), def_group_index))); return vertex_group.name; } diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh index 390d8034337..f3ace140006 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh @@ -32,6 +32,7 @@ #include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "DNA_object_types.h" #include "IO_wavefront_obj.h" @@ -57,7 +58,11 @@ using unique_bmesh_ptr = std::unique_ptr<BMesh, CustomBMeshDeleter>; class OBJMesh : NonCopyable { private: - Object *export_object_eval_; + /** + * We need to copy the entire Object structure here because the dependency graph iterator + * sometimes builds an Object in a temporary space that doesn't persist. + */ + Object export_object_eval_; Mesh *export_mesh_eval_; /** * For curves which are converted to mesh, and triangulated meshes, a new mesh is allocated. @@ -85,7 +90,7 @@ class OBJMesh : NonCopyable { * Total number of normal indices (maximum entry, plus 1, in * the loop_to_norm_index_ vector). */ - int tot_normal_indices_ = NEGATIVE_INIT; + int tot_normal_indices_ = 0; /** * Total smooth groups in an object. */ diff --git a/source/blender/io/wavefront_obj/exporter/obj_exporter.cc b/source/blender/io/wavefront_obj/exporter/obj_exporter.cc index 595e6aaf4f2..0c753ccdcac 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_exporter.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_exporter.cc @@ -91,28 +91,29 @@ filter_supported_objects(Depsgraph *depsgraph, const OBJExportParams &export_par { Vector<std::unique_ptr<OBJMesh>> r_exportable_meshes; Vector<std::unique_ptr<OBJCurve>> r_exportable_nurbs; - const ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph); - LISTBASE_FOREACH (const Base *, base, &view_layer->object_bases) { - Object *object_in_layer = base->object; - if (export_params.export_selected_objects && !(object_in_layer->base_flag & BASE_SELECTED)) { + const int deg_objects_visibility_flags = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | + DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET | + DEG_ITER_OBJECT_FLAG_VISIBLE | + DEG_ITER_OBJECT_FLAG_DUPLI; + DEG_OBJECT_ITER_BEGIN (depsgraph, object, deg_objects_visibility_flags) { + if (export_params.export_selected_objects && !(object->base_flag & BASE_SELECTED)) { continue; } - switch (object_in_layer->type) { + switch (object->type) { case OB_SURF: /* Export in mesh form: vertices and polygons. */ ATTR_FALLTHROUGH; case OB_MESH: - r_exportable_meshes.append( - std::make_unique<OBJMesh>(depsgraph, export_params, object_in_layer)); + r_exportable_meshes.append(std::make_unique<OBJMesh>(depsgraph, export_params, object)); break; case OB_CURVE: { - Curve *curve = static_cast<Curve *>(object_in_layer->data); + Curve *curve = static_cast<Curve *>(object->data); Nurb *nurb{static_cast<Nurb *>(curve->nurb.first)}; if (!nurb) { /* An empty curve. Not yet supported to export these as meshes. */ if (export_params.export_curves_as_nurbs) { r_exportable_nurbs.append( - std::make_unique<OBJCurve>(depsgraph, export_params, object_in_layer)); + std::make_unique<OBJCurve>(depsgraph, export_params, object)); } break; } @@ -121,18 +122,18 @@ filter_supported_objects(Depsgraph *depsgraph, const OBJExportParams &export_par if (export_params.export_curves_as_nurbs) { /* Export in parameter form: control points. */ r_exportable_nurbs.append( - std::make_unique<OBJCurve>(depsgraph, export_params, object_in_layer)); + std::make_unique<OBJCurve>(depsgraph, export_params, object)); } else { /* Export in mesh form: edges and vertices. */ r_exportable_meshes.append( - std::make_unique<OBJMesh>(depsgraph, export_params, object_in_layer)); + std::make_unique<OBJMesh>(depsgraph, export_params, object)); } break; case CU_BEZIER: /* Always export in mesh form: edges and vertices. */ r_exportable_meshes.append( - std::make_unique<OBJMesh>(depsgraph, export_params, object_in_layer)); + std::make_unique<OBJMesh>(depsgraph, export_params, object)); break; default: /* Other curve types are not supported. */ @@ -145,6 +146,7 @@ filter_supported_objects(Depsgraph *depsgraph, const OBJExportParams &export_par break; } } + DEG_OBJECT_ITER_END; return {std::move(r_exportable_meshes), std::move(r_exportable_nurbs)}; } diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc index 92d478c20a1..5dac913c902 100644 --- a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc +++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc @@ -60,7 +60,7 @@ TEST_F(obj_exporter_test, filter_objects_curves_as_mesh) return; } auto [objmeshes, objcurves]{filter_supported_objects(depsgraph, _export.params)}; - EXPECT_EQ(objmeshes.size(), 17); + EXPECT_EQ(objmeshes.size(), 19); EXPECT_EQ(objcurves.size(), 0); } @@ -73,7 +73,7 @@ TEST_F(obj_exporter_test, filter_objects_curves_as_nurbs) } _export.params.export_curves_as_nurbs = true; auto [objmeshes, objcurves]{filter_supported_objects(depsgraph, _export.params)}; - EXPECT_EQ(objmeshes.size(), 16); + EXPECT_EQ(objmeshes.size(), 18); EXPECT_EQ(objcurves.size(), 2); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc index 9001cb2d1f2..840dfd2fbd3 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc @@ -48,8 +48,8 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); - uiItemR(layout, ptr, "domain", 0, "", ICON_NONE); uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); + uiItemR(layout, ptr, "domain", 0, "", ICON_NONE); } static void node_init(bNodeTree *UNUSED(tree), bNode *node) diff --git a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc index a257af4391c..d17657bfa3a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc @@ -44,7 +44,7 @@ static void node_declare(NodeDeclarationBuilder &b) b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); b.add_input<decl::Float>(N_("Distance Min")).min(0.0f).subtype(PROP_DISTANCE); b.add_input<decl::Float>(N_("Density Max")).default_value(10.0f).min(0.0f); - b.add_input<decl::Float>(N_("Density")).default_value(10.0f).supports_field(); + b.add_input<decl::Float>(N_("Density")).default_value(10.0f).min(0.0f).supports_field(); b.add_input<decl::Float>(N_("Density Factor")) .default_value(1.0f) .min(0.0f) |