diff options
author | Hans Goudey <h.goudey@me.com> | 2022-09-13 05:47:59 +0300 |
---|---|---|
committer | Hans Goudey <h.goudey@me.com> | 2022-09-13 05:47:59 +0300 |
commit | 2edb69f8a600847f195b88deceea5e980ecb61a7 (patch) | |
tree | a58387c1a28f893281eb54838f1673c00bbeb614 /source/blender | |
parent | c8808542d0365877e1345a708931320ffe71b098 (diff) | |
parent | 400151833db01928a62a13b12f047cd0f90c6ed2 (diff) |
Merge branch 'master' into refactor-mesh-position-generic
Diffstat (limited to 'source/blender')
85 files changed, 1172 insertions, 766 deletions
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index ceadd036a2a..68ce3ca7318 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -140,14 +140,6 @@ struct DerivedMesh { void (*copyLoopArray)(DerivedMesh *dm, struct MLoop *r_loop); void (*copyPolyArray)(DerivedMesh *dm, struct MPoly *r_poly); - /** Return a copy of all verts/edges/faces from the derived mesh - * it is the caller's responsibility to free the returned pointer - */ - struct MVert *(*dupVertArray)(DerivedMesh *dm); - struct MEdge *(*dupEdgeArray)(DerivedMesh *dm); - struct MLoop *(*dupLoopArray)(DerivedMesh *dm); - struct MPoly *(*dupPolyArray)(DerivedMesh *dm); - /** Return a pointer to the entire array of vert/edge/face custom data * from the derived mesh (this gives a pointer to the actual data, not * a copy) @@ -253,11 +245,6 @@ void DM_copy_vert_data(struct DerivedMesh *source, int count); /** - * Sets up mpolys for a DM based on face iterators in source. - */ -void DM_DupPolys(DerivedMesh *source, DerivedMesh *target); - -/** * Ensure the array is large enough. * * \note This function must always be thread-protected by caller. diff --git a/source/blender/blenkernel/BKE_attribute.hh b/source/blender/blenkernel/BKE_attribute.hh index 4aa6c133e9e..21d91af55d5 100644 --- a/source/blender/blenkernel/BKE_attribute.hh +++ b/source/blender/blenkernel/BKE_attribute.hh @@ -553,6 +553,11 @@ class MutableAttributeAccessor : public AttributeAccessor { GAttributeWriter lookup_for_write(const AttributeIDRef &attribute_id); /** + * Same as above, but returns a type that makes it easier to work with the attribute as a span. + */ + GSpanAttributeWriter lookup_for_write_span(const AttributeIDRef &attribute_id); + + /** * Get a writable attribute or non if it does not exist. * Make sure to call #finish after changes are done. */ @@ -569,6 +574,19 @@ class MutableAttributeAccessor : public AttributeAccessor { } /** + * Same as above, but returns a type that makes it easier to work with the attribute as a span. + */ + template<typename T> + SpanAttributeWriter<T> lookup_for_write_span(const AttributeIDRef &attribute_id) + { + AttributeWriter<T> attribute = this->lookup_for_write<T>(attribute_id); + if (attribute) { + return SpanAttributeWriter<T>{std::move(attribute), true}; + } + return {}; + } + + /** * Create a new attribute. * \return True, when a new attribute has been created. False, when it's not possible to create * this attribute or there is already an attribute with that id. diff --git a/source/blender/blenkernel/BKE_cdderivedmesh.h b/source/blender/blenkernel/BKE_cdderivedmesh.h index 3c929857c14..2d1aca7c3c8 100644 --- a/source/blender/blenkernel/BKE_cdderivedmesh.h +++ b/source/blender/blenkernel/BKE_cdderivedmesh.h @@ -25,10 +25,6 @@ struct Mesh; * data to not overwrite the original. */ struct DerivedMesh *CDDM_from_mesh(struct Mesh *mesh); -/* Copies the given DerivedMesh with verts, faces & edges stored as - * custom element data. */ -struct DerivedMesh *CDDM_copy(struct DerivedMesh *source); - #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index 09d37682b3c..24fa5f0e87a 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -178,13 +178,11 @@ bool CustomData_merge_mesh_to_bmesh(const struct CustomData *source, int totelem); /** - * Reallocate custom data to a new element count. - * Only affects on data layers which are owned by the CustomData itself, - * referenced data is kept unchanged, - * - * \note Take care of referenced layers by yourself! + * Reallocate custom data to a new element count. If the new size is larger, the new values use + * the #CD_CONSTRUCT behavior, so trivial types must be initialized by the caller. After being + * resized, the #CustomData does not contain any referenced layers. */ -void CustomData_realloc(struct CustomData *data, int totelem); +void CustomData_realloc(struct CustomData *data, int old_size, int new_size); /** * BMesh version of CustomData_merge; merges the layouts of source and `dest`, diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 49a303ade70..a5453b6eebd 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -212,9 +212,7 @@ bool BKE_paint_always_hide_test(struct Object *ob); /** * Returns non-zero if any of the face's vertices are hidden, zero otherwise. */ -bool paint_is_face_hidden(const struct MLoopTri *lt, - const bool *hide_vert, - const struct MLoop *mloop); +bool paint_is_face_hidden(const struct MLoopTri *lt, const bool *hide_poly); /** * Returns non-zero if any of the corners of the grid * face whose inner corner is at (x, y) are hidden, zero otherwise. @@ -688,7 +686,7 @@ void BKE_sculpt_update_object_for_edit(struct Depsgraph *depsgraph, bool need_pmap, bool need_mask, bool is_paint_tool); -void BKE_sculpt_update_object_before_eval(const struct Scene *scene, struct Object *ob_eval); +void BKE_sculpt_update_object_before_eval(struct Object *ob_eval); void BKE_sculpt_update_object_after_eval(struct Depsgraph *depsgraph, struct Object *ob_eval); /** @@ -697,6 +695,7 @@ void BKE_sculpt_update_object_after_eval(struct Depsgraph *depsgraph, struct Obj */ struct MultiresModifierData *BKE_sculpt_multires_active(const struct Scene *scene, struct Object *ob); +int *BKE_sculpt_face_sets_ensure(struct Mesh *mesh); int BKE_sculpt_mask_layers_ensure(struct Object *ob, struct MultiresModifierData *mmd); void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene); @@ -718,18 +717,17 @@ void BKE_sculpt_sync_face_sets_visibility_to_grids(struct Mesh *mesh, struct SubdivCCG *subdiv_ccg); /** - * Ensures that a Face Set data-layers exists. If it does not, it creates one respecting the - * visibility stored in the vertices of the mesh. If it does, it copies the visibility from the - * mesh to the Face Sets. */ -void BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(struct Mesh *mesh); + * If a face set layer exists, initialize its visiblity (sign) from the mesh's hidden values. + */ +void BKE_sculpt_face_sets_update_from_base_mesh_visibility(struct Mesh *mesh); /** - * Ensures we do have expected mesh data in original mesh for the sculpt mode. + * Makes sculpt data consistent with other data on the mesh. * * \note IDs are expected to be original ones here, and calling code should ensure it updates its * depsgraph properly after calling this function if it needs up-to-date evaluated data. */ -void BKE_sculpt_ensure_orig_mesh_data(struct Scene *scene, struct Object *object); +void BKE_sculpt_ensure_orig_mesh_data(struct Object *object); /** * Test if PBVH can be used directly for drawing, which is faster than diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index 3abc62b2070..037b02c1acb 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -670,6 +670,8 @@ const float (*BKE_pbvh_get_vert_normals(const PBVH *pbvh))[3]; const bool *BKE_pbvh_get_vert_hide(const PBVH *pbvh); bool *BKE_pbvh_get_vert_hide_for_write(PBVH *pbvh); +const bool *BKE_pbvh_get_poly_hide(const PBVH *pbvh); + PBVHColorBufferNode *BKE_pbvh_node_color_buffer_get(PBVHNode *node); void BKE_pbvh_node_color_buffer_free(PBVH *pbvh); bool BKE_pbvh_get_color_layer(const struct Mesh *me, diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc index dda9ee20e58..790f549b12d 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.cc +++ b/source/blender/blenkernel/intern/DerivedMesh.cc @@ -148,54 +148,6 @@ static MPoly *dm_getPolyArray(DerivedMesh *dm) return mpoly; } -static MVert *dm_dupVertArray(DerivedMesh *dm) -{ - MVert *tmp = (MVert *)MEM_malloc_arrayN( - dm->getNumVerts(dm), sizeof(*tmp), "dm_dupVertArray tmp"); - - if (tmp) { - dm->copyVertArray(dm, tmp); - } - - return tmp; -} - -static MEdge *dm_dupEdgeArray(DerivedMesh *dm) -{ - MEdge *tmp = (MEdge *)MEM_malloc_arrayN( - dm->getNumEdges(dm), sizeof(*tmp), "dm_dupEdgeArray tmp"); - - if (tmp) { - dm->copyEdgeArray(dm, tmp); - } - - return tmp; -} - -static MLoop *dm_dupLoopArray(DerivedMesh *dm) -{ - MLoop *tmp = (MLoop *)MEM_malloc_arrayN( - dm->getNumLoops(dm), sizeof(*tmp), "dm_dupLoopArray tmp"); - - if (tmp) { - dm->copyLoopArray(dm, tmp); - } - - return tmp; -} - -static MPoly *dm_dupPolyArray(DerivedMesh *dm) -{ - MPoly *tmp = (MPoly *)MEM_malloc_arrayN( - dm->getNumPolys(dm), sizeof(*tmp), "dm_dupPolyArray tmp"); - - if (tmp) { - dm->copyPolyArray(dm, tmp); - } - - return tmp; -} - static int dm_getNumLoopTri(DerivedMesh *dm) { const int numlooptris = poly_to_tri_count(dm->getNumPolys(dm), dm->getNumLoops(dm)); @@ -234,10 +186,6 @@ void DM_init_funcs(DerivedMesh *dm) dm->getEdgeArray = dm_getEdgeArray; dm->getLoopArray = dm_getLoopArray; dm->getPolyArray = dm_getPolyArray; - dm->dupVertArray = dm_dupVertArray; - dm->dupEdgeArray = dm_dupEdgeArray; - dm->dupLoopArray = dm_dupLoopArray; - dm->dupPolyArray = dm_dupPolyArray; dm->getLoopTriArray = dm_getLoopTriArray; @@ -332,36 +280,6 @@ bool DM_release(DerivedMesh *dm) return false; } -void DM_DupPolys(DerivedMesh *source, DerivedMesh *target) -{ - CustomData_free(&target->loopData, source->numLoopData); - CustomData_free(&target->polyData, source->numPolyData); - - CustomData_copy(&source->loopData, - &target->loopData, - CD_MASK_DERIVEDMESH.lmask, - CD_DUPLICATE, - source->numLoopData); - CustomData_copy(&source->polyData, - &target->polyData, - CD_MASK_DERIVEDMESH.pmask, - CD_DUPLICATE, - source->numPolyData); - - target->numLoopData = source->numLoopData; - target->numPolyData = source->numPolyData; - - if (!CustomData_has_layer(&target->polyData, CD_MPOLY)) { - MPoly *mpoly; - MLoop *mloop; - - mloop = source->dupLoopArray(source); - mpoly = source->dupPolyArray(source); - CustomData_add_layer(&target->loopData, CD_MLOOP, CD_ASSIGN, mloop, source->numLoopData); - CustomData_add_layer(&target->polyData, CD_MPOLY, CD_ASSIGN, mpoly, source->numPolyData); - } -} - void DM_ensure_looptri_data(DerivedMesh *dm) { const unsigned int totpoly = dm->numPolyData; @@ -1803,7 +1721,7 @@ void makeDerivedMesh(struct Depsgraph *depsgraph, BKE_object_free_derived_caches(ob); if (DEG_is_active(depsgraph)) { - BKE_sculpt_update_object_before_eval(scene, ob); + BKE_sculpt_update_object_before_eval(ob); } /* NOTE: Access the `edit_mesh` after freeing the derived caches, so that `ob->data` is restored diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c index 24e4305d916..96ac81fdb63 100644 --- a/source/blender/blenkernel/intern/appdir.c +++ b/source/blender/blenkernel/intern/appdir.c @@ -371,14 +371,16 @@ static bool get_path_local_ex(char *targetpath, relfolder[0] = '\0'; } - /* Try `{g_app.program_dirname}/2.xx/{folder_name}` the default directory + /* Try `{g_app.program_dirname}/3.xx/{folder_name}` the default directory * for a portable distribution. See `WITH_INSTALL_PORTABLE` build-option. */ const char *path_base = g_app.program_dirname; #if defined(__APPLE__) && !defined(WITH_PYTHON_MODULE) /* Due new code-sign situation in OSX > 10.9.5 - * we must move the blender_version dir with contents to Resources. */ - char osx_resourses[FILE_MAX]; - BLI_snprintf(osx_resourses, sizeof(osx_resourses), "%s../Resources", g_app.program_dirname); + * we must move the blender_version dir with contents to Resources. + * Add 4 + 9 for the temporary `/../` path & `Resources`. */ + char osx_resourses[FILE_MAX + 4 + 9]; + BLI_path_join( + osx_resourses, sizeof(osx_resourses), g_app.program_dirname, "..", "Resources", NULL); /* Remove the '/../' added above. */ BLI_path_normalize(NULL, osx_resourses); path_base = osx_resourses; diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index 6ca3a286a5e..27c54a3d4a7 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -726,8 +726,22 @@ bool CustomDataAttributes::remove(const AttributeIDRef &attribute_id) void CustomDataAttributes::reallocate(const int size) { + const int old_size = size_; size_ = size; - CustomData_realloc(&data, size); + CustomData_realloc(&data, old_size, size_); + if (size_ > old_size) { + /* Fill default new values. */ + const int new_elements_num = size_ - old_size; + this->foreach_attribute( + [&](const bke::AttributeIDRef &id, const bke::AttributeMetaData /*meta_data*/) { + GMutableSpan new_data = this->get_for_write(id)->take_back(new_elements_num); + const CPPType &type = new_data.type(); + type.fill_assign_n(type.default_value(), new_data.data(), new_data.size()); + return true; + }, + /* Dummy. */ + ATTR_DOMAIN_POINT); + } } void CustomDataAttributes::clear() @@ -875,6 +889,16 @@ GAttributeWriter MutableAttributeAccessor::lookup_for_write(const AttributeIDRef return attribute; } +GSpanAttributeWriter MutableAttributeAccessor::lookup_for_write_span( + const AttributeIDRef &attribute_id) +{ + GAttributeWriter attribute = this->lookup_for_write(attribute_id); + if (attribute) { + return GSpanAttributeWriter{std::move(attribute), true}; + } + return {}; +} + GAttributeWriter MutableAttributeAccessor::lookup_or_add_for_write( const AttributeIDRef &attribute_id, const eAttrDomain domain, diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index ab70596a739..e3dd26c0a20 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -244,44 +244,4 @@ DerivedMesh *CDDM_from_mesh(Mesh *mesh) { return cdDM_from_mesh_ex(mesh, CD_REFERENCE, &CD_MASK_MESH); } - -DerivedMesh *CDDM_copy(DerivedMesh *source) -{ - CDDerivedMesh *cddm = cdDM_create("CDDM_copy cddm"); - DerivedMesh *dm = &cddm->dm; - int numVerts = source->numVertData; - int numEdges = source->numEdgeData; - int numTessFaces = 0; - int numLoops = source->numLoopData; - int numPolys = source->numPolyData; - - /* NOTE: Don't copy tessellation faces if not requested explicitly. */ - - /* ensure these are created if they are made on demand */ - source->getVertDataArray(source, CD_ORIGINDEX); - source->getEdgeDataArray(source, CD_ORIGINDEX); - source->getPolyDataArray(source, CD_ORIGINDEX); - - /* this initializes dm, and copies all non mvert/medge/mface layers */ - DM_from_template(dm, source, DM_TYPE_CDDM, numVerts, numEdges, numTessFaces, numLoops, numPolys); - dm->deformedOnly = source->deformedOnly; - dm->cd_flag = source->cd_flag; - - CustomData_copy_data(&source->vertData, &dm->vertData, 0, 0, numVerts); - CustomData_copy_data(&source->edgeData, &dm->edgeData, 0, 0, numEdges); - - /* now add mvert/medge/mface layers */ - cddm->positions = source->dupVertArray(source); - cddm->medge = source->dupEdgeArray(source); - - CustomData_add_layer_named( - &dm->vertData, CD_PROP_FLOAT3, CD_ASSIGN, cddm->positions, numVerts, "position"); - CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_ASSIGN, cddm->medge, numEdges); - - DM_DupPolys(source, dm); - - cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP); - cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY); - - return dm; -} +<<<<<<< HEAD diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc index 35b209179d3..1b4508d99c1 100644 --- a/source/blender/blenkernel/intern/curves_geometry.cc +++ b/source/blender/blenkernel/intern/curves_geometry.cc @@ -963,11 +963,11 @@ void CurvesGeometry::ensure_can_interpolate_to_evaluated() const void CurvesGeometry::resize(const int points_num, const int curves_num) { if (points_num != this->point_num) { - CustomData_realloc(&this->point_data, points_num); + CustomData_realloc(&this->point_data, this->points_num(), points_num); this->point_num = points_num; } if (curves_num != this->curve_num) { - CustomData_realloc(&this->curve_data, curves_num); + CustomData_realloc(&this->curve_data, this->curves_num(), curves_num); this->curve_num = curves_num; this->curve_offsets = (int *)MEM_reallocN(this->curve_offsets, sizeof(int) * (curves_num + 1)); } @@ -1392,57 +1392,47 @@ static bool layer_matches_name_and_type(const CustomDataLayer &layer, void CurvesGeometry::reverse_curves(const IndexMask curves_to_reverse) { - CustomData_duplicate_referenced_layers(&this->point_data, this->points_num()); + Set<StringRef> bezier_handle_names{{ATTR_HANDLE_POSITION_LEFT, + ATTR_HANDLE_POSITION_RIGHT, + ATTR_HANDLE_TYPE_LEFT, + ATTR_HANDLE_TYPE_RIGHT}}; - /* Collect the Bezier handle attributes while iterating through the point custom data layers; - * they need special treatment later. */ - MutableSpan<float3> positions_left; - MutableSpan<float3> positions_right; - MutableSpan<int8_t> types_left; - MutableSpan<int8_t> types_right; + MutableAttributeAccessor attributes = this->attributes_for_write(); - for (const int layer_i : IndexRange(this->point_data.totlayer)) { - CustomDataLayer &layer = this->point_data.layers[layer_i]; - - if (positions_left.is_empty() && - layer_matches_name_and_type(layer, ATTR_HANDLE_POSITION_LEFT, CD_PROP_FLOAT3)) { - positions_left = {static_cast<float3 *>(layer.data), this->points_num()}; - continue; - } - if (positions_right.is_empty() && - layer_matches_name_and_type(layer, ATTR_HANDLE_POSITION_RIGHT, CD_PROP_FLOAT3)) { - positions_right = {static_cast<float3 *>(layer.data), this->points_num()}; - continue; - } - if (types_left.is_empty() && - layer_matches_name_and_type(layer, ATTR_HANDLE_TYPE_LEFT, CD_PROP_INT8)) { - types_left = {static_cast<int8_t *>(layer.data), this->points_num()}; - continue; + attributes.for_all([&](const AttributeIDRef &id, AttributeMetaData meta_data) { + if (meta_data.domain != ATTR_DOMAIN_POINT) { + return true; } - if (types_right.is_empty() && - layer_matches_name_and_type(layer, ATTR_HANDLE_TYPE_RIGHT, CD_PROP_INT8)) { - types_right = {static_cast<int8_t *>(layer.data), this->points_num()}; - continue; + if (id.is_named() && bezier_handle_names.contains(id.name())) { + return true; } - const eCustomDataType data_type = static_cast<eCustomDataType>(layer.type); - attribute_math::convert_to_static_type(data_type, [&](auto dummy) { + GSpanAttributeWriter attribute = attributes.lookup_for_write_span(id); + attribute_math::convert_to_static_type(attribute.span.type(), [&](auto dummy) { using T = decltype(dummy); - reverse_curve_point_data<T>( - *this, curves_to_reverse, {static_cast<T *>(layer.data), this->points_num()}); + reverse_curve_point_data<T>(*this, curves_to_reverse, attribute.span.typed<T>()); }); - } + attribute.finish(); + return true; + }); /* In order to maintain the shape of Bezier curves, handle attributes must reverse, but also the * values for the left and right must swap. Use a utility to swap and reverse at the same time, * to avoid loading the attribute twice. Generally we can expect the right layer to exist when * the left does, but there's no need to count on it, so check for both attributes. */ - if (!positions_left.is_empty() && !positions_right.is_empty()) { - reverse_swap_curve_point_data(*this, curves_to_reverse, positions_left, positions_right); + if (attributes.contains(ATTR_HANDLE_POSITION_LEFT) && + attributes.contains(ATTR_HANDLE_POSITION_RIGHT)) { + reverse_swap_curve_point_data(*this, + curves_to_reverse, + this->handle_positions_left_for_write(), + this->handle_positions_right_for_write()); } - if (!types_left.is_empty() && !types_right.is_empty()) { - reverse_swap_curve_point_data(*this, curves_to_reverse, types_left, types_right); + if (attributes.contains(ATTR_HANDLE_TYPE_LEFT) && attributes.contains(ATTR_HANDLE_TYPE_RIGHT)) { + reverse_swap_curve_point_data(*this, + curves_to_reverse, + this->handle_types_left_for_write(), + this->handle_types_right_for_write()); } this->tag_topology_changed(); @@ -1450,21 +1440,20 @@ void CurvesGeometry::reverse_curves(const IndexMask curves_to_reverse) void CurvesGeometry::remove_attributes_based_on_types() { - const int points_num = this->points_num(); - const int curves_num = this->curves_num(); + MutableAttributeAccessor attributes = this->attributes_for_write(); if (!this->has_curve_with_type(CURVE_TYPE_BEZIER)) { - CustomData_free_layer_named(&this->point_data, ATTR_HANDLE_TYPE_LEFT.c_str(), points_num); - CustomData_free_layer_named(&this->point_data, ATTR_HANDLE_TYPE_RIGHT.c_str(), points_num); - CustomData_free_layer_named(&this->point_data, ATTR_HANDLE_POSITION_LEFT.c_str(), points_num); - CustomData_free_layer_named(&this->point_data, ATTR_HANDLE_POSITION_RIGHT.c_str(), points_num); + attributes.remove(ATTR_HANDLE_TYPE_LEFT); + attributes.remove(ATTR_HANDLE_TYPE_RIGHT); + attributes.remove(ATTR_HANDLE_POSITION_LEFT); + attributes.remove(ATTR_HANDLE_POSITION_RIGHT); } if (!this->has_curve_with_type(CURVE_TYPE_NURBS)) { - CustomData_free_layer_named(&this->point_data, ATTR_NURBS_WEIGHT.c_str(), points_num); - CustomData_free_layer_named(&this->curve_data, ATTR_NURBS_ORDER.c_str(), curves_num); - CustomData_free_layer_named(&this->curve_data, ATTR_NURBS_KNOTS_MODE.c_str(), curves_num); + attributes.remove(ATTR_NURBS_WEIGHT); + attributes.remove(ATTR_NURBS_ORDER); + attributes.remove(ATTR_NURBS_KNOTS_MODE); } if (!this->has_curve_with_type({CURVE_TYPE_BEZIER, CURVE_TYPE_CATMULL_ROM, CURVE_TYPE_NURBS})) { - CustomData_free_layer_named(&this->curve_data, ATTR_RESOLUTION.c_str(), curves_num); + attributes.remove(ATTR_RESOLUTION); } } diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index a5c93e205b9..bf56fb7f044 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -2415,19 +2415,37 @@ bool CustomData_merge_mesh_to_bmesh(const CustomData *source, return result; } -void CustomData_realloc(CustomData *data, const int totelem) +void CustomData_realloc(CustomData *data, const int old_size, const int new_size) { - BLI_assert(totelem >= 0); + BLI_assert(new_size >= 0); for (int i = 0; i < data->totlayer; i++) { CustomDataLayer *layer = &data->layers[i]; - const LayerTypeInfo *typeInfo; + const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type); + + const int64_t old_size_in_bytes = int64_t(old_size) * typeInfo->size; + const int64_t new_size_in_bytes = int64_t(new_size) * typeInfo->size; if (layer->flag & CD_FLAG_NOFREE) { - continue; + const void *old_data = layer->data; + layer->data = MEM_malloc_arrayN(new_size, typeInfo->size, __func__); + if (typeInfo->copy) { + typeInfo->copy(old_data, layer->data, std::min(old_size, new_size)); + } + else { + std::memcpy(layer->data, old_data, std::min(old_size_in_bytes, new_size_in_bytes)); + } + layer->flag &= ~CD_FLAG_NOFREE; + } + else { + layer->data = MEM_reallocN(layer->data, new_size_in_bytes); + } + + if (new_size > old_size) { + /* Initialize new values for non-trivial types. */ + if (typeInfo->construct) { + const int new_elements_num = new_size - old_size; + typeInfo->construct(POINTER_OFFSET(layer->data, old_size_in_bytes), new_elements_num); + } } - typeInfo = layerType_getInfo(layer->type); - /* Use calloc to avoid the need to manually initialize new data in layers. - * Useful for types like #MDeformVert which contain a pointer. */ - layer->data = MEM_recallocN(layer->data, (size_t)totelem * typeInfo->size); } } diff --git a/source/blender/blenkernel/intern/image_save.cc b/source/blender/blenkernel/intern/image_save.cc index e65a94d5301..6f62ee123cb 100644 --- a/source/blender/blenkernel/intern/image_save.cc +++ b/source/blender/blenkernel/intern/image_save.cc @@ -175,12 +175,12 @@ bool BKE_image_save_options_init(ImageSaveOptions *opts, BLI_strncpy(opts->filepath, G.ima, sizeof(opts->filepath)); } else { - BLI_snprintf(opts->filepath, sizeof(opts->filepath), "//%s", DATA_("untitled")); + BLI_path_join(opts->filepath, sizeof(opts->filepath), "//", DATA_("untitled"), nullptr); BLI_path_abs(opts->filepath, BKE_main_blendfile_path(bmain)); } } else { - BLI_snprintf(opts->filepath, sizeof(opts->filepath), "//%s", ima->id.name + 2); + BLI_path_join(opts->filepath, sizeof(opts->filepath), "//", ima->id.name + 2, nullptr); BLI_path_make_safe(opts->filepath); BLI_path_abs(opts->filepath, is_prev_save ? G.ima : BKE_main_blendfile_path(bmain)); } diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 965c8487f9a..58397da202f 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -1414,19 +1414,15 @@ void BKE_mesh_material_remap(Mesh *me, const uint *remap, uint remap_len) } else { MutableAttributeAccessor attributes = me->attributes_for_write(); - AttributeWriter<int> material_indices = attributes.lookup_for_write<int>("material_index"); + SpanAttributeWriter<int> material_indices = attributes.lookup_or_add_for_write_span<int>( + "material_index", ATTR_DOMAIN_FACE); if (!material_indices) { return; } - if (material_indices.domain != ATTR_DOMAIN_FACE) { - BLI_assert_unreachable(); - return; - } - MutableVArraySpan<int> indices_span(material_indices.varray); - for (const int i : indices_span.index_range()) { - MAT_NR_REMAP(indices_span[i]); + for (const int i : material_indices.span.index_range()) { + MAT_NR_REMAP(material_indices.span[i]); } - indices_span.save(); + material_indices.span.save(); material_indices.finish(); } @@ -2081,11 +2077,11 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals) const bool do_edges = (num_new_edges > 0); /* Reallocate all vert and edge related data. */ + CustomData_realloc(&mesh->vdata, mesh->totvert, mesh->totvert + num_new_verts); mesh->totvert += num_new_verts; - CustomData_realloc(&mesh->vdata, mesh->totvert); if (do_edges) { + CustomData_realloc(&mesh->edata, mesh->totedge, mesh->totedge + num_new_edges); mesh->totedge += num_new_edges; - CustomData_realloc(&mesh->edata, mesh->totedge); } /* Update normals manually to avoid recalculation after this operation. */ diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc index d57212e3d6d..0ae6e1e4a1f 100644 --- a/source/blender/blenkernel/intern/mesh_convert.cc +++ b/source/blender/blenkernel/intern/mesh_convert.cc @@ -105,8 +105,9 @@ static void make_edges_mdata_extend(Mesh &mesh) #endif if (totedge_new) { - CustomData_realloc(&mesh.edata, totedge + totedge_new); - + /* The only layer should be edges, so no other layers need to be initialized. */ + BLI_assert(mesh.edata.totlayer == 1); + CustomData_realloc(&mesh.edata, totedge, totedge + totedge_new); mesh.totedge += totedge_new; MutableSpan<MEdge> edges = mesh.edges_for_write(); MEdge *medge = &edges[totedge]; @@ -629,9 +630,11 @@ void BKE_pointcloud_from_mesh(Mesh *me, PointCloud *pointcloud) using namespace blender; BLI_assert(me != nullptr); - + /* The pointcloud should only contain the position attribute, otherwise more attributes would + * need to be initialized below. */ + BLI_assert(pointcloud->attributes().all_ids().size() == 1); + CustomData_realloc(&pointcloud->pdata, pointcloud->totpoint, me->totvert); pointcloud->totpoint = me->totvert; - CustomData_realloc(&pointcloud->pdata, pointcloud->totpoint); /* Copy over all attributes. */ CustomData_merge(&me->vdata, &pointcloud->pdata, CD_MASK_PROP_ALL, CD_DUPLICATE, me->totvert); diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index 9457c20eb7d..da508ff865c 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -1241,7 +1241,7 @@ static NlaStrip *nlastrip_find_active(ListBase /* NlaStrip */ *strips) float BKE_nlastrip_compute_frame_from_previous_strip(NlaStrip *strip) { - float limit_prev = MINFRAMEF; + float limit_prev = MINAFRAMEF; /* Find the previous end frame, with a special case if the previous strip was a transition : */ if (strip->prev) { diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c index 7c96c463339..901b42ac0b2 100644 --- a/source/blender/blenkernel/intern/packedFile.c +++ b/source/blender/blenkernel/intern/packedFile.c @@ -526,21 +526,27 @@ static void unpack_generate_paths(const char *name, BLI_strncpy(tempdir, "//", sizeof(tempdir)); } - switch (id_type) { - case ID_VF: - BLI_snprintf(r_relpath, relpathlen, "//fonts/%s", tempname); - break; - case ID_SO: - BLI_snprintf(r_relpath, relpathlen, "//sounds/%s", tempname); - break; - case ID_IM: - BLI_snprintf(r_relpath, relpathlen, "//textures/%s", tempname); - break; - case ID_VO: - BLI_snprintf(r_relpath, relpathlen, "//volumes/%s", tempname); - break; - default: - break; + { + const char *dir_name = NULL; + switch (id_type) { + case ID_VF: + dir_name = "fonts"; + break; + case ID_SO: + dir_name = "sounds"; + break; + case ID_IM: + dir_name = "textures"; + break; + case ID_VO: + dir_name = "volumes"; + break; + default: + break; + } + if (dir_name) { + BLI_path_join(r_relpath, relpathlen, "//", dir_name, tempname, NULL); + } } { diff --git a/source/blender/blenkernel/intern/paint.cc b/source/blender/blenkernel/intern/paint.cc index ca09567cb6b..ce004b6664a 100644 --- a/source/blender/blenkernel/intern/paint.cc +++ b/source/blender/blenkernel/intern/paint.cc @@ -1089,10 +1089,10 @@ bool BKE_paint_ensure(ToolSettings *ts, Paint **r_paint) Sculpt *data = MEM_cnew<Sculpt>(__func__); paint = &data->paint; - /* Turn on X plane mirror symmetry by default */ + /* Turn on X plane mirror symmetry by default. */ paint->symmetry_flags |= PAINT_SYMM_X; - /* Make sure at least dyntopo subdivision is enabled */ + /* Make sure at least dyntopo subdivision is enabled. */ data->flags |= SCULPT_DYNTOPO_SUBDIVIDE | SCULPT_DYNTOPO_COLLAPSE; } else if ((GpPaint **)r_paint == &ts->gp_paint) { @@ -1147,7 +1147,7 @@ void BKE_paint_init(Main *bmain, Scene *sce, ePaintMode mode, const uchar col[3] brush = BKE_brush_first_search(bmain, ob_mode); if (!brush) { brush = BKE_brush_add(bmain, "Brush", ob_mode); - id_us_min(&brush->id); /* fake user only */ + id_us_min(&brush->id); /* Fake user only. */ } BKE_paint_brush_set(paint, brush); } @@ -1248,18 +1248,17 @@ void BKE_paint_blend_read_lib(BlendLibReader *reader, Scene *sce, Paint *p) } } -bool paint_is_face_hidden(const MLoopTri *lt, const bool *hide_vert, const MLoop *mloop) +bool paint_is_face_hidden(const MLoopTri *lt, const bool *hide_poly) { - if (!hide_vert) { + if (!hide_poly) { return false; } - return ((hide_vert[mloop[lt->tri[0]].v]) || (hide_vert[mloop[lt->tri[1]].v]) || - (hide_vert[mloop[lt->tri[2]].v])); + return hide_poly[lt->poly]; } bool paint_is_grid_face_hidden(const uint *grid_hidden, int gridsize, int x, int y) { - /* skip face if any of its corners are hidden */ + /* Skip face if any of its corners are hidden. */ return (BLI_BITMAP_TEST(grid_hidden, y * gridsize + x) || BLI_BITMAP_TEST(grid_hidden, y * gridsize + x + 1) || BLI_BITMAP_TEST(grid_hidden, (y + 1) * gridsize + x + 1) || @@ -1289,7 +1288,7 @@ float paint_grid_paint_mask(const GridPaintMask *gpm, uint level, uint x, uint y return gpm->data[(y * factor) * gridsize + (x * factor)]; } -/* threshold to move before updating the brush rotation */ +/* Threshold to move before updating the brush rotation. */ #define RAKE_THRESHHOLD 20 void paint_update_brush_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, float rotation) @@ -1332,8 +1331,8 @@ bool paint_calculate_rake_rotation(UnifiedPaintSettings *ups, paint_update_brush_rake_rotation(ups, brush, rotation); ok = true; } - /* make sure we reset here to the last rotation to avoid accumulating - * values in case a random rotation is also added */ + /* Make sure we reset here to the last rotation to avoid accumulating + * values in case a random rotation is also added. */ else { paint_update_brush_rake_rotation(ups, brush, ups->last_rake_angle); ok = false; @@ -1529,20 +1528,29 @@ void BKE_sculptsession_free(Object *ob) } } -MultiresModifierData *BKE_sculpt_multires_active(const Scene *scene, Object *ob) +static MultiresModifierData *sculpt_multires_modifier_get(const Scene *scene, + Object *ob, + const bool auto_create_mdisps) { Mesh *me = (Mesh *)ob->data; ModifierData *md; VirtualModifierData virtualModifierData; if (ob->sculpt && ob->sculpt->bm) { - /* can't combine multires and dynamic topology */ + /* Can't combine multires and dynamic topology. */ return nullptr; } + bool need_mdisps = false; + if (!CustomData_get_layer(&me->ldata, CD_MDISPS)) { - /* multires can't work without displacement layer */ - return nullptr; + if (!auto_create_mdisps) { + /* Multires can't work without displacement layer. */ + return nullptr; + } + else { + need_mdisps = true; + } } /* Weight paint operates on original vertices, and needs to treat multires as regular modifier @@ -1560,6 +1568,10 @@ MultiresModifierData *BKE_sculpt_multires_active(const Scene *scene, Object *ob) } if (mmd->sculptlvl > 0 && !(mmd->flags & eMultiresModifierFlag_UseSculptBaseMesh)) { + if (need_mdisps) { + CustomData_add_layer(&me->ldata, CD_MDISPS, CD_SET_DEFAULT, nullptr, me->totloop); + } + return mmd; } @@ -1570,6 +1582,11 @@ MultiresModifierData *BKE_sculpt_multires_active(const Scene *scene, Object *ob) return nullptr; } +MultiresModifierData *BKE_sculpt_multires_active(const Scene *scene, Object *ob) +{ + return sculpt_multires_modifier_get(scene, ob, false); +} + /* Checks if there are any supported deformation modifiers active */ static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob) { @@ -1581,14 +1598,14 @@ static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob) return false; } - /* non-locked shape keys could be handled in the same way as deformed mesh */ + /* Non-locked shape keys could be handled in the same way as deformed mesh. */ if ((ob->shapeflag & OB_SHAPE_LOCK) == 0 && me->key && ob->shapenr) { return true; } md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); - /* exception for shape keys because we can edit those */ + /* Exception for shape keys because we can edit those. */ for (; md; md = md->next) { const ModifierTypeInfo *mti = BKE_modifier_get_info(static_cast<ModifierType>(md->type)); if (!BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) { @@ -1615,22 +1632,15 @@ static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob) return false; } -/** - * \param need_mask: So that the evaluated mesh that is returned has mask data. - */ -static void sculpt_update_object(Depsgraph *depsgraph, - Object *ob, - Object *ob_eval, - bool need_pmap, - bool need_mask, - bool is_paint_tool) +static void sculpt_update_object( + Depsgraph *depsgraph, Object *ob, Object *ob_eval, bool need_pmap, bool is_paint_tool) { Scene *scene = DEG_get_input_scene(depsgraph); Sculpt *sd = scene->toolsettings->sculpt; SculptSession *ss = ob->sculpt; Mesh *me = BKE_object_get_original_mesh(ob); Mesh *me_eval = BKE_object_get_evaluated_mesh(ob_eval); - MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob); + MultiresModifierData *mmd = sculpt_multires_modifier_get(scene, ob, true); const bool use_face_sets = (ob->mode & OB_MODE_SCULPT) != 0; BLI_assert(me_eval != nullptr); @@ -1645,15 +1655,6 @@ static void sculpt_update_object(Depsgraph *depsgraph, ss->scene = scene; - if (need_mask) { - if (mmd == nullptr) { - BLI_assert(CustomData_has_layer(&me->vdata, CD_PAINT_MASK)); - } - else { - BLI_assert(CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK)); - } - } - ss->shapekey_active = (mmd == nullptr) ? BKE_keyblock_from_object(ob) : nullptr; /* NOTE: Weight pPaint require mesh info for loop lookup, but it never uses multires code path, @@ -1709,7 +1710,6 @@ static void sculpt_update_object(Depsgraph *depsgraph, /* Sculpt Face Sets. */ if (use_face_sets) { - BLI_assert(CustomData_has_layer(&me->pdata, CD_SCULPT_FACE_SETS)); ss->face_sets = static_cast<int *>(CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS)); } else { @@ -1842,24 +1842,7 @@ static void sculpt_update_object(Depsgraph *depsgraph, } } -static void sculpt_face_sets_ensure(Mesh *mesh) -{ - if (CustomData_has_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)) { - return; - } - - int *new_face_sets = static_cast<int *>(CustomData_add_layer( - &mesh->pdata, CD_SCULPT_FACE_SETS, CD_CONSTRUCT, nullptr, mesh->totpoly)); - - /* Initialize the new Face Set data-layer with a default valid visible ID and set the default - * color to render it white. */ - for (int i = 0; i < mesh->totpoly; i++) { - new_face_sets[i] = 1; - } - mesh->face_sets_color_default = 1; -} - -void BKE_sculpt_update_object_before_eval(const Scene *scene, Object *ob_eval) +void BKE_sculpt_update_object_before_eval(Object *ob_eval) { /* Update before mesh evaluation in the dependency graph. */ SculptSession *ss = ob_eval->sculpt; @@ -1889,16 +1872,6 @@ void BKE_sculpt_update_object_before_eval(const Scene *scene, Object *ob_eval) MEM_freeN(nodes); } } - - if (ss) { - Object *ob_orig = DEG_get_original_object(ob_eval); - Mesh *mesh = BKE_object_get_original_mesh(ob_orig); - MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob_orig); - - /* Ensure attribute layout is still correct. */ - sculpt_face_sets_ensure(mesh); - BKE_sculpt_mask_layers_ensure(ob_orig, mmd); - } } void BKE_sculpt_update_object_after_eval(Depsgraph *depsgraph, Object *ob_eval) @@ -1907,7 +1880,7 @@ void BKE_sculpt_update_object_after_eval(Depsgraph *depsgraph, Object *ob_eval) * other data when modifiers change the mesh. */ Object *ob_orig = DEG_get_original_object(ob_eval); - sculpt_update_object(depsgraph, ob_orig, ob_eval, false, false, false); + sculpt_update_object(depsgraph, ob_orig, ob_eval, false, false); } void BKE_sculpt_color_layer_create_if_needed(Object *object) @@ -1945,13 +1918,53 @@ void BKE_sculpt_color_layer_create_if_needed(Object *object) } void BKE_sculpt_update_object_for_edit( - Depsgraph *depsgraph, Object *ob_orig, bool need_pmap, bool need_mask, bool is_paint_tool) + Depsgraph *depsgraph, Object *ob_orig, bool need_pmap, bool /*need_mask*/, bool is_paint_tool) { BLI_assert(ob_orig == DEG_get_original_object(ob_orig)); Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob_orig); - sculpt_update_object(depsgraph, ob_orig, ob_eval, need_pmap, need_mask, is_paint_tool); + sculpt_update_object(depsgraph, ob_orig, ob_eval, need_pmap, is_paint_tool); +} + +int *BKE_sculpt_face_sets_ensure(Mesh *mesh) +{ + using namespace blender; + using namespace blender::bke; + if (CustomData_has_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)) { + return static_cast<int *>(CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)); + } + + const AttributeAccessor attributes = mesh->attributes_for_write(); + const VArray<bool> hide_poly = attributes.lookup_or_default<bool>( + ".hide_poly", ATTR_DOMAIN_FACE, false); + + MutableSpan<int> face_sets = { + static_cast<int *>(CustomData_add_layer( + &mesh->pdata, CD_SCULPT_FACE_SETS, CD_CONSTRUCT, nullptr, mesh->totpoly)), + mesh->totpoly}; + + /* Initialize the new face sets with a default valid visible ID and set the default + * color to render it white. */ + if (hide_poly.is_single() && !hide_poly.get_internal_single()) { + face_sets.fill(1); + } + else { + const int face_sets_default_visible_id = 1; + const int face_sets_default_hidden_id = -2; + + const VArraySpan<bool> hide_poly_span{hide_poly}; + for (const int i : face_sets.index_range()) { + /* Assign a new hidden ID to hidden faces. This way we get at initial split in two Face Sets + * between hidden and visible faces based on the previous mesh visibly from other mode that + * can be useful in some cases. */ + face_sets[i] = hide_poly_span[i] ? face_sets_default_hidden_id : + face_sets_default_visible_id; + } + } + + mesh->face_sets_color_default = 1; + return face_sets.data(); } int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd) @@ -2015,7 +2028,7 @@ int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd) ret |= SCULPT_MASK_LAYER_CALC_LOOP; } - /* create vertex paint mask layer if there isn't one already */ + /* Create vertex paint mask layer if there isn't one already. */ if (!paint_mask) { CustomData_add_layer(&me->vdata, CD_PAINT_MASK, CD_SET_DEFAULT, nullptr, me->totvert); ret |= SCULPT_MASK_LAYER_CALC_VERT; @@ -2039,7 +2052,7 @@ void BKE_sculpt_toolsettings_data_ensure(Scene *scene) sd->constant_detail = 3.0f; } - /* Set sane default tiling offsets */ + /* Set sane default tiling offsets. */ if (!sd->paint.tile_offset[0]) { sd->paint.tile_offset[0] = 1.0f; } @@ -2057,8 +2070,7 @@ static bool check_sculpt_object_deformed(Object *object, const bool for_construc /* Active modifiers means extra deformation, which can't be handled correct * on birth of PBVH and sculpt "layer" levels, so use PBVH only for internal brush - * stuff and show final evaluated mesh so user would see actual object shape. - */ + * stuff and show final evaluated mesh so user would see actual object shape. */ deformed |= object->sculpt->deform_modifiers_active; if (for_construction) { @@ -2067,75 +2079,55 @@ static bool check_sculpt_object_deformed(Object *object, const bool for_construc else { /* As in case with modifiers, we can't synchronize deformation made against * PBVH and non-locked keyblock, so also use PBVH only for brushes and - * final DM to give final result to user. - */ + * final DM to give final result to user. */ deformed |= object->sculpt->shapekey_active && (object->shapeflag & OB_SHAPE_LOCK) == 0; } return deformed; } -void BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(Mesh *mesh) +void BKE_sculpt_face_sets_update_from_base_mesh_visibility(Mesh *mesh) { - const int face_sets_default_visible_id = 1; - const int face_sets_default_hidden_id = -(face_sets_default_visible_id + 1); - - bool initialize_new_face_sets = false; - - if (CustomData_has_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)) { - /* Make everything visible. */ - int *current_face_sets = static_cast<int *>( - CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)); - for (int i = 0; i < mesh->totpoly; i++) { - current_face_sets[i] = abs(current_face_sets[i]); - } - } - else { - initialize_new_face_sets = true; - int *new_face_sets = static_cast<int *>(CustomData_add_layer( - &mesh->pdata, CD_SCULPT_FACE_SETS, CD_CONSTRUCT, nullptr, mesh->totpoly)); - - /* Initialize the new Face Set data-layer with a default valid visible ID and set the default - * color to render it white. */ - for (int i = 0; i < mesh->totpoly; i++) { - new_face_sets[i] = face_sets_default_visible_id; - } - mesh->face_sets_color_default = face_sets_default_visible_id; + using namespace blender; + using namespace blender::bke; + if (!CustomData_has_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)) { + return; } - int *face_sets = static_cast<int *>(CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)); - const bool *hide_poly = (const bool *)CustomData_get_layer_named( - &mesh->pdata, CD_PROP_BOOL, ".hide_poly"); + const AttributeAccessor attributes = mesh->attributes(); + const VArray<bool> hide_poly = attributes.lookup_or_default<bool>( + ".hide_poly", ATTR_DOMAIN_FACE, false); + if (hide_poly.is_single() && !hide_poly.get_internal_single()) { + return; + } - for (int i = 0; i < mesh->totpoly; i++) { - if (!(hide_poly && hide_poly[i])) { - continue; - } + MutableSpan<int> face_sets{ + static_cast<int *>(CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)), mesh->totpoly}; - if (initialize_new_face_sets) { - /* When initializing a new Face Set data-layer, assign a new hidden Face Set ID to hidden - * vertices. This way, we get at initial split in two Face Sets between hidden and - * visible vertices based on the previous mesh visibly from other mode that can be - * useful in some cases. */ - face_sets[i] = face_sets_default_hidden_id; - } - else { - /* Otherwise, set the already existing Face Set ID to hidden. */ - face_sets[i] = -abs(face_sets[i]); - } + for (const int i : hide_poly.index_range()) { + face_sets[i] = hide_poly[i] ? -std::abs(face_sets[i]) : std::abs(face_sets[i]); } } -void BKE_sculpt_sync_face_sets_visibility_to_base_mesh(Mesh *mesh) +static void set_hide_poly_from_face_sets(Mesh &mesh) { + using namespace blender; using namespace blender::bke; - const int *face_sets = static_cast<const int *>( - CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)); - if (!face_sets) { + if (!CustomData_has_layer(&mesh.pdata, CD_SCULPT_FACE_SETS)) { + return; + } + + const Span<int> face_sets{ + static_cast<const int *>(CustomData_get_layer(&mesh.pdata, CD_SCULPT_FACE_SETS)), + mesh.totpoly}; + + MutableAttributeAccessor attributes = mesh.attributes_for_write(); + if (std::all_of( + face_sets.begin(), face_sets.end(), [&](const int value) { return value > 0; })) { + attributes.remove(".hide_poly"); return; } - MutableAttributeAccessor attributes = mesh->attributes_for_write(); SpanAttributeWriter<bool> hide_poly = attributes.lookup_or_add_for_write_only_span<bool>( ".hide_poly", ATTR_DOMAIN_FACE); if (!hide_poly) { @@ -2145,7 +2137,11 @@ void BKE_sculpt_sync_face_sets_visibility_to_base_mesh(Mesh *mesh) hide_poly.span[i] = face_sets[i] < 0; } hide_poly.finish(); +} +void BKE_sculpt_sync_face_sets_visibility_to_base_mesh(Mesh *mesh) +{ + set_hide_poly_from_face_sets(*mesh); BKE_mesh_flush_hidden_from_polys(mesh); } @@ -2183,41 +2179,29 @@ void BKE_sculpt_sync_face_sets_visibility_to_grids(Mesh *mesh, SubdivCCG *subdiv void BKE_sculpt_sync_face_set_visibility(Mesh *mesh, SubdivCCG *subdiv_ccg) { - BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(mesh); + BKE_sculpt_face_sets_update_from_base_mesh_visibility(mesh); BKE_sculpt_sync_face_sets_visibility_to_base_mesh(mesh); BKE_sculpt_sync_face_sets_visibility_to_grids(mesh, subdiv_ccg); } -void BKE_sculpt_ensure_orig_mesh_data(Scene *scene, Object *object) +void BKE_sculpt_ensure_orig_mesh_data(Object *object) { Mesh *mesh = BKE_mesh_from_object(object); - MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, object); - BLI_assert(object->mode == OB_MODE_SCULPT); /* Copy the current mesh visibility to the Face Sets. */ - BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(mesh); - if (object->sculpt != nullptr) { - /* If a sculpt session is active, ensure we have its face-set data properly up-to-date. */ - object->sculpt->face_sets = static_cast<int *>( - CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)); - - /* NOTE: In theory we could add that on the fly when required by sculpt code. - * But this then requires proper update of depsgraph etc. For now we play safe, optimization is - * always possible later if it's worth it. */ - BKE_sculpt_mask_layers_ensure(object, mmd); - } + BKE_sculpt_face_sets_update_from_base_mesh_visibility(mesh); /* Tessfaces aren't used and will become invalid. */ BKE_mesh_tessface_clear(mesh); /* We always need to flush updates from depsgraph here, since at the very least - * `BKE_sculpt_face_sets_ensure_from_base_mesh_visibility()` will have updated some data layer of + * `BKE_sculpt_face_sets_update_from_base_mesh_visibility()` will have updated some data layer of * the mesh. * * All known potential sources of updates: * - Addition of, or changes to, the `CD_SCULPT_FACE_SETS` data layer - * (`BKE_sculpt_face_sets_ensure_from_base_mesh_visibility`). + * (`BKE_sculpt_face_sets_update_from_base_mesh_visibility`). * - Addition of a `CD_PAINT_MASK` data layer (`BKE_sculpt_mask_layers_ensure`). * - Object has any active modifier (modifier stack can be different in Sculpt mode). * - Multires: diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index b1cb8862776..d63a52c383c 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -285,7 +285,7 @@ static void build_mesh_leaf_node(PBVH *pbvh, PBVHNode *node) } if (has_visible == false) { - if (!paint_is_face_hidden(lt, pbvh->hide_vert, pbvh->mloop)) { + if (!paint_is_face_hidden(lt, pbvh->hide_poly)) { has_visible = true; } } @@ -552,6 +552,7 @@ void BKE_pbvh_build_mesh(PBVH *pbvh, pbvh->mesh = mesh; pbvh->header.type = PBVH_FACES; pbvh->mpoly = mpoly; + pbvh->hide_poly = (bool *)CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, ".hide_poly"); pbvh->material_indices = (const int *)CustomData_get_layer_named( &mesh->pdata, CD_PROP_INT32, "material_index"); pbvh->mloop = mloop; @@ -1313,11 +1314,7 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata, } case PBVH_FACES: node->draw_buffers = GPU_pbvh_mesh_buffers_build( - pbvh->mesh, - pbvh->looptri, - CustomData_get_layer(pbvh->pdata, CD_SCULPT_FACE_SETS), - node->prim_indices, - node->totprim); + pbvh->mesh, pbvh->looptri, node->prim_indices, node->totprim); break; case PBVH_BMESH: node->draw_buffers = GPU_pbvh_bmesh_buffers_build(pbvh->flags & @@ -2282,7 +2279,7 @@ static bool pbvh_faces_node_raycast(PBVH *pbvh, const MLoopTri *lt = &pbvh->looptri[faces[i]]; const int *face_verts = node->face_vert_indices[i]; - if (pbvh->respect_hide && paint_is_face_hidden(lt, pbvh->hide_vert, mloop)) { + if (pbvh->respect_hide && paint_is_face_hidden(lt, pbvh->hide_poly)) { continue; } @@ -2591,7 +2588,7 @@ static bool pbvh_faces_node_nearest_to_ray(PBVH *pbvh, const MLoopTri *lt = &pbvh->looptri[faces[i]]; const int *face_verts = node->face_vert_indices[i]; - if (pbvh->respect_hide && paint_is_face_hidden(lt, pbvh->hide_vert, mloop)) { + if (pbvh->respect_hide && paint_is_face_hidden(lt, pbvh->hide_poly)) { continue; } @@ -3202,6 +3199,12 @@ const bool *BKE_pbvh_get_vert_hide(const PBVH *pbvh) return pbvh->hide_vert; } +const bool *BKE_pbvh_get_poly_hide(const PBVH *pbvh) +{ + BLI_assert(pbvh->header.type == PBVH_FACES); + return pbvh->hide_poly; +} + bool *BKE_pbvh_get_vert_hide_for_write(PBVH *pbvh) { BLI_assert(pbvh->header.type == PBVH_FACES); diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h index 91533994932..00681e31c10 100644 --- a/source/blender/blenkernel/intern/pbvh_intern.h +++ b/source/blender/blenkernel/intern/pbvh_intern.h @@ -156,6 +156,7 @@ struct PBVH { bool *hide_vert; float (*positions)[3]; const struct MPoly *mpoly; + bool *hide_poly; /** Material indices. Only valid for polygon meshes. */ const int *material_indices; const struct MLoop *mloop; diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc index fe6353bc72d..b45e164b594 100644 --- a/source/blender/blenkernel/intern/pointcloud.cc +++ b/source/blender/blenkernel/intern/pointcloud.cc @@ -189,8 +189,9 @@ IDTypeInfo IDType_ID_PT = { static void pointcloud_random(PointCloud *pointcloud) { + BLI_assert(pointcloud->totpoint == 0); pointcloud->totpoint = 400; - CustomData_realloc(&pointcloud->pdata, pointcloud->totpoint); + CustomData_realloc(&pointcloud->pdata, 0, pointcloud->totpoint); RNG *rng = BLI_rng_new(0); @@ -238,9 +239,6 @@ PointCloud *BKE_pointcloud_new_nomain(const int totpoint) nullptr, ID_PT, BKE_idtype_idcode_to_name(ID_PT), LIB_ID_CREATE_LOCALIZE)); pointcloud_init_data(&pointcloud->id); - - pointcloud->totpoint = totpoint; - CustomData_add_layer_named(&pointcloud->pdata, CD_PROP_FLOAT, CD_SET_DEFAULT, @@ -248,8 +246,8 @@ PointCloud *BKE_pointcloud_new_nomain(const int totpoint) pointcloud->totpoint, POINTCLOUD_ATTR_RADIUS); + CustomData_realloc(&pointcloud->pdata, 0, totpoint); pointcloud->totpoint = totpoint; - CustomData_realloc(&pointcloud->pdata, pointcloud->totpoint); return pointcloud; } diff --git a/source/blender/blenlib/BLI_generic_span.hh b/source/blender/blenlib/BLI_generic_span.hh index 143ab235d2e..e7a08988c46 100644 --- a/source/blender/blenlib/BLI_generic_span.hh +++ b/source/blender/blenlib/BLI_generic_span.hh @@ -100,6 +100,34 @@ class GSpan { { return this->slice(range.start(), range.size()); } + + GSpan drop_front(const int64_t n) const + { + BLI_assert(n >= 0); + const int64_t new_size = std::max<int64_t>(0, size_ - n); + return GSpan(*type_, POINTER_OFFSET(data_, type_->size() * n), new_size); + } + + GSpan drop_back(const int64_t n) const + { + BLI_assert(n >= 0); + const int64_t new_size = std::max<int64_t>(0, size_ - n); + return GSpan(*type_, data_, new_size); + } + + GSpan take_front(const int64_t n) const + { + BLI_assert(n >= 0); + const int64_t new_size = std::min<int64_t>(size_, n); + return GSpan(*type_, data_, new_size); + } + + GSpan take_back(const int64_t n) const + { + BLI_assert(n >= 0); + const int64_t new_size = std::min<int64_t>(size_, n); + return GSpan(*type_, POINTER_OFFSET(data_, type_->size() * (size_ - new_size)), new_size); + } }; /** @@ -199,6 +227,35 @@ class GMutableSpan { return this->slice(range.start(), range.size()); } + GMutableSpan drop_front(const int64_t n) const + { + BLI_assert(n >= 0); + const int64_t new_size = std::max<int64_t>(0, size_ - n); + return GMutableSpan(*type_, POINTER_OFFSET(data_, type_->size() * n), new_size); + } + + GMutableSpan drop_back(const int64_t n) const + { + BLI_assert(n >= 0); + const int64_t new_size = std::max<int64_t>(0, size_ - n); + return GMutableSpan(*type_, data_, new_size); + } + + GMutableSpan take_front(const int64_t n) const + { + BLI_assert(n >= 0); + const int64_t new_size = std::min<int64_t>(size_, n); + return GMutableSpan(*type_, data_, new_size); + } + + GMutableSpan take_back(const int64_t n) const + { + BLI_assert(n >= 0); + const int64_t new_size = std::min<int64_t>(size_, n); + return GMutableSpan( + *type_, POINTER_OFFSET(data_, type_->size() * (size_ - new_size)), new_size); + } + /** * Copy all values from another span into this span. This invokes undefined behavior when the * destination contains uninitialized data and T is not trivially copy constructible. diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h index 75002f52d94..136258e50f2 100644 --- a/source/blender/blenlib/BLI_path_util.h +++ b/source/blender/blenlib/BLI_path_util.h @@ -84,10 +84,18 @@ void BLI_join_dirfile(char *__restrict dst, * Join multiple strings into a path, ensuring only a single path separator between each, * and trailing slash is kept. * + * \param path: The first patch which has special treatment, + * allowing `//` prefix which is kept intact unlike double-slashes which are stripped + * from the bounds of all other paths passed in. + * Passing in the following paths all result in the same output (`//a/b/c`): + * - `"//", "a", "b", "c"`. + * - `"//", "/a/", "/b/", "/c"`. + * - `"//a", "b/c"`. + * * \note If you want a trailing slash, add `SEP_STR` as the last path argument, * duplicate slashes will be cleaned up. */ -size_t BLI_path_join(char *__restrict dst, size_t dst_len, const char *path_first, ...) +size_t BLI_path_join(char *__restrict dst, size_t dst_len, const char *path, ...) ATTR_NONNULL(1, 3) ATTR_SENTINEL(0); /** * Like Python's `os.path.basename()` diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index 1e95aa3b7b0..c053c3907db 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -1505,8 +1505,8 @@ size_t BLI_path_join(char *__restrict dst, const size_t dst_len, const char *pat return ofs; } - /* remove trailing slashes, unless there are _only_ trailing slashes - * (allow "//" as the first argument). */ + /* Remove trailing slashes, unless there are *only* trailing slashes + * (allow `//` or `//some_path` as the first argument). */ bool has_trailing_slash = false; if (ofs != 0) { size_t len = ofs; diff --git a/source/blender/blenlib/tests/BLI_path_util_test.cc b/source/blender/blenlib/tests/BLI_path_util_test.cc index 4f6f4a5c413..54afc3d975d 100644 --- a/source/blender/blenlib/tests/BLI_path_util_test.cc +++ b/source/blender/blenlib/tests/BLI_path_util_test.cc @@ -298,6 +298,13 @@ TEST(path_util, JoinComplex) JOIN("1/2/3/", 100, "1", "////////", "", "2", "3\\"); } +TEST(path_util, JoinRelativePrefix) +{ + JOIN("//a/b/c", 100, "//a", "b", "c"); + JOIN("//a/b/c", 100, "//", "//a//", "//b//", "//c"); + JOIN("//a/b/c", 100, "//", "//", "a", "//", "b", "//", "c"); +} + #undef JOIN /* BLI_path_frame */ diff --git a/source/blender/compositor/operations/COM_ViewerOperation.cc b/source/blender/compositor/operations/COM_ViewerOperation.cc index aeadf8f255d..3bd5fa4ad14 100644 --- a/source/blender/compositor/operations/COM_ViewerOperation.cc +++ b/source/blender/compositor/operations/COM_ViewerOperation.cc @@ -156,7 +156,7 @@ void ViewerOperation::init_image() ibuf->y = display_height_; /* zero size can happen if no image buffers exist to define a sensible resolution */ if (ibuf->x > 0 && ibuf->y > 0) { - imb_addrectfloatImBuf(ibuf); + imb_addrectfloatImBuf(ibuf, 4); } ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.cc b/source/blender/draw/intern/draw_cache_impl_mesh.cc index e60689f0237..c22382b3e09 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.cc +++ b/source/blender/draw/intern/draw_cache_impl_mesh.cc @@ -556,8 +556,7 @@ static bool mesh_batch_cache_valid(Object *object, Mesh *me) } if (object->sculpt && object->sculpt->pbvh) { - if (cache->pbvh_is_drawing != BKE_pbvh_is_drawing(object->sculpt->pbvh) || - BKE_pbvh_draw_cache_invalid(object->sculpt->pbvh)) { + if (cache->pbvh_is_drawing != BKE_pbvh_is_drawing(object->sculpt->pbvh)) { return false; } diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 89ab9eda7f0..d28cefd4887 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -67,6 +67,7 @@ #include "ED_armature.h" #include "ED_gpencil.h" +#include "ED_keyframing.h" #include "ED_object.h" #include "ED_outliner.h" #include "ED_screen.h" @@ -1715,10 +1716,15 @@ static int gpencil_strokes_paste_exec(bContext *C, wmOperator *op) /* Ensure we have a frame to draw into * NOTE: Since this is an op which creates strokes, - * we are obliged to add a new frame if one - * doesn't exist already + * we resuse active frame or add a new frame if one + * doesn't exist already depending on REC button status. */ - gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_ADD_NEW); + if (IS_AUTOKEY_ON(scene) || (gpl->actframe == NULL)) { + gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_ADD_NEW); + } + else { + gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_USE_PREV); + } if (gpf) { /* Create new stroke */ bGPDstroke *new_stroke = BKE_gpencil_stroke_duplicate(gps, true, true); diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index b6a652bd3ab..26743a2bd08 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -139,6 +139,7 @@ struct UvElementMap *BM_uv_element_map_create(struct BMesh *bm, const struct Scene *scene, bool uv_selected, bool use_winding, + 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, diff --git a/source/blender/editors/io/io_obj.c b/source/blender/editors/io/io_obj.c index 66e95c019f6..619d8a34132 100644 --- a/source/blender/editors/io/io_obj.c +++ b/source/blender/editors/io/io_obj.c @@ -125,7 +125,7 @@ static void ui_obj_export_settings(uiLayout *layout, PointerRNA *imfptr) uiItemR(sub, imfptr, "scaling_factor", 0, NULL, ICON_NONE); row = uiLayoutRow(box, false); - uiItemR(row, imfptr, "forward_axis", UI_ITEM_R_EXPAND, IFACE_("Foward Axis"), ICON_NONE); + uiItemR(row, imfptr, "forward_axis", UI_ITEM_R_EXPAND, IFACE_("Forward Axis"), ICON_NONE); row = uiLayoutRow(box, false); uiItemR(row, imfptr, "up_axis", UI_ITEM_R_EXPAND, IFACE_("Up Axis"), ICON_NONE); diff --git a/source/blender/editors/io/io_usd.c b/source/blender/editors/io/io_usd.c index ba118a5e289..eb80cabcd7f 100644 --- a/source/blender/editors/io/io_usd.c +++ b/source/blender/editors/io/io_usd.c @@ -191,6 +191,19 @@ static void wm_usd_export_draw(bContext *UNUSED(C), wmOperator *op) uiItemR(box, ptr, "use_instancing", 0, NULL, ICON_NONE); } +static void free_operator_customdata(wmOperator *op) +{ + if (op->customdata) { + MEM_freeN(op->customdata); + op->customdata = NULL; + } +} + +static void wm_usd_export_cancel(bContext *UNUSED(C), wmOperator *op) +{ + free_operator_customdata(op); +} + static bool wm_usd_export_check(bContext *UNUSED(C), wmOperator *op) { char filepath[FILE_MAX]; @@ -215,6 +228,7 @@ void WM_OT_usd_export(struct wmOperatorType *ot) ot->exec = wm_usd_export_exec; ot->poll = WM_operator_winactive; ot->ui = wm_usd_export_draw; + ot->cancel = wm_usd_export_cancel; ot->check = wm_usd_export_check; ot->flag = OPTYPE_REGISTER | OPTYPE_PRESET; /* No UNDO possible. */ @@ -360,7 +374,7 @@ static int wm_usd_import_exec(bContext *C, wmOperator *op) const bool create_collection = RNA_boolean_get(op->ptr, "create_collection"); - char *prim_path_mask = malloc(1024); + char prim_path_mask[1024]; RNA_string_get(op->ptr, "prim_path_mask", prim_path_mask); const bool import_guide = RNA_boolean_get(op->ptr, "import_guide"); @@ -402,7 +416,6 @@ static int wm_usd_import_exec(bContext *C, wmOperator *op) .import_materials = import_materials, .import_meshes = import_meshes, .import_volumes = import_volumes, - .prim_path_mask = prim_path_mask, .import_subdiv = import_subdiv, .import_instance_proxies = import_instance_proxies, .create_collection = create_collection, @@ -416,11 +429,18 @@ static int wm_usd_import_exec(bContext *C, wmOperator *op) .light_intensity_scale = light_intensity_scale, .mtl_name_collision_mode = mtl_name_collision_mode}; + STRNCPY(params.prim_path_mask, prim_path_mask); + const bool ok = USD_import(C, filename, ¶ms, as_background_job); return as_background_job || ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } +static void wm_usd_import_cancel(bContext *UNUSED(C), wmOperator *op) +{ + free_operator_customdata(op); +} + static void wm_usd_import_draw(bContext *UNUSED(C), wmOperator *op) { uiLayout *layout = op->layout; @@ -476,6 +496,7 @@ void WM_OT_usd_import(struct wmOperatorType *ot) ot->invoke = wm_usd_import_invoke; ot->exec = wm_usd_import_exec; + ot->cancel = wm_usd_import_cancel; ot->poll = WM_operator_winactive; ot->ui = wm_usd_import_draw; diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index a6a6b095c31..cca2aa11ac3 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -851,10 +851,99 @@ static void bm_uv_build_islands(UvElementMap *element_map, MEM_SAFE_FREE(map); } +/* return true if `loop` has UV co-ordinates which match `luv_a` and `luv_b` */ +static bool loop_uv_match(BMLoop *loop, MLoopUV *luv_a, MLoopUV *luv_b, int cd_loop_uv_offset) +{ + MLoopUV *luv_c = BM_ELEM_CD_GET_VOID_P(loop, cd_loop_uv_offset); + MLoopUV *luv_d = BM_ELEM_CD_GET_VOID_P(loop->next, cd_loop_uv_offset); + return compare_v2v2(luv_a->uv, luv_c->uv, STD_UV_CONNECT_LIMIT) && + compare_v2v2(luv_b->uv, luv_d->uv, STD_UV_CONNECT_LIMIT); +} + +/* Given `anchor` and `edge`, return true if there are edges that fan between them that are + * seam-free. */ +static bool seam_connected_recursive(BMVert *anchor, + BMEdge *edge, + MLoopUV *luv_anchor, + MLoopUV *luv_fan, + BMLoop *needle, + GSet *visited, + int cd_loop_uv_offset) +{ + BLI_assert(edge->v1 == anchor || edge->v2 == anchor); + BLI_assert(needle->v == anchor || needle->next->v == anchor); + + if (BM_elem_flag_test(edge, BM_ELEM_SEAM)) { + return false; /* Edge is a seam, don't traverse. */ + } + + if (!BLI_gset_add(visited, edge)) { + return false; /* Already visited. */ + } + + BMLoop *loop; + BMIter liter; + BM_ITER_ELEM (loop, &liter, edge, BM_LOOPS_OF_EDGE) { + if (loop->v == anchor) { + if (!loop_uv_match(loop, luv_anchor, luv_fan, cd_loop_uv_offset)) { + continue; /* `loop` is disjoint in UV space. */ + } + + if (loop->prev == needle) { + return true; /* Success. */ + } + + MLoopUV *luv_far = BM_ELEM_CD_GET_VOID_P(loop->prev, cd_loop_uv_offset); + if (seam_connected_recursive( + anchor, loop->prev->e, luv_anchor, luv_far, needle, visited, cd_loop_uv_offset)) { + return true; + } + } + else { + BLI_assert(loop->next->v == anchor); + if (!loop_uv_match(loop, luv_fan, luv_anchor, cd_loop_uv_offset)) { + continue; /* `loop` is disjoint in UV space. */ + } + + if (loop->next == needle) { + return true; /* Success. */ + } + + MLoopUV *luv_far = BM_ELEM_CD_GET_VOID_P(loop->next->next, cd_loop_uv_offset); + if (seam_connected_recursive( + anchor, loop->next->e, luv_anchor, luv_far, needle, visited, cd_loop_uv_offset)) { + return true; + } + } + } + + return false; +} + +/* Given `loop_a` and `loop_b` originate from the same vertex and share a UV, + * return true if there are edges that fan between them that are seam-free. + * return false otherwise. + */ +static bool seam_connected(BMLoop *loop_a, BMLoop *loop_b, GSet *visited, int cd_loop_uv_offset) +{ + BLI_assert(loop_a && loop_b); + BLI_assert(loop_a != loop_b); + BLI_assert(loop_a->v == loop_b->v); + + BLI_gset_clear(visited, NULL); + + MLoopUV *luv_anchor = BM_ELEM_CD_GET_VOID_P(loop_a, cd_loop_uv_offset); + MLoopUV *luv_fan = BM_ELEM_CD_GET_VOID_P(loop_a->next, cd_loop_uv_offset); + const bool result = seam_connected_recursive( + loop_a->v, loop_a->e, luv_anchor, luv_fan, loop_b, visited, cd_loop_uv_offset); + return result; +} + UvElementMap *BM_uv_element_map_create(BMesh *bm, const Scene *scene, const bool uv_selected, const bool use_winding, + const bool use_seams, const bool do_islands) { /* In uv sync selection, all UVs are visible. */ @@ -956,6 +1045,8 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, } BLI_buffer_free(&tf_uv_buf); + GSet *seam_visited_gset = use_seams ? BLI_gset_ptr_new(__func__) : NULL; + /* For each BMVert, sort associated linked list into unique uvs. */ int ev_index; BM_ITER_MESH_INDEX (ev, &iter, bm, BM_VERTS_OF_MESH, ev_index) { @@ -1001,6 +1092,10 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, winding[BM_elem_index_get(v->l->f)]; } + if (connected && use_seams) { + connected = seam_connected(iterv->l, v->l, seam_visited_gset, cd_loop_uv_offset); + } + if (connected) { if (lastv) { lastv->next = next; @@ -1026,6 +1121,10 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm, element_map->vertex[ev_index] = newvlist; } + if (seam_visited_gset) { + BLI_gset_free(seam_visited_gset, NULL); + seam_visited_gset = NULL; + } MEM_SAFE_FREE(winding); /* at this point, every UvElement in vert points to a UvElement sharing the same vertex. diff --git a/source/blender/editors/object/object_remesh.cc b/source/blender/editors/object/object_remesh.cc index c85c8f9535a..2fb6257885c 100644 --- a/source/blender/editors/object/object_remesh.cc +++ b/source/blender/editors/object/object_remesh.cc @@ -186,7 +186,7 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op) } if (ob->mode == OB_MODE_SCULPT) { - BKE_sculpt_ensure_orig_mesh_data(CTX_data_scene(C), ob); + BKE_sculpt_ensure_orig_mesh_data(ob); ED_sculpt_undo_geometry_end(ob); } @@ -910,7 +910,7 @@ static void quadriflow_start_job(void *customdata, short *stop, short *do_update } if (ob->mode == OB_MODE_SCULPT) { - BKE_sculpt_ensure_orig_mesh_data(qj->scene, ob); + BKE_sculpt_ensure_orig_mesh_data(ob); ED_sculpt_undo_geometry_end(ob); } diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index 24337477585..ac7002e9e43 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -134,6 +134,7 @@ static void mask_flood_fill_task_cb(void *__restrict userdata, static int mask_flood_fill_exec(bContext *C, wmOperator *op) { + const Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); PaintMaskFloodMode mode; @@ -146,6 +147,9 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op) mode = RNA_enum_get(op->ptr, "mode"); value = RNA_float_get(op->ptr, "value"); + MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob); + BKE_sculpt_mask_layers_ensure(ob, mmd); + BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true, false); pbvh = ob->sculpt->pbvh; multires = (BKE_pbvh_type(pbvh) == PBVH_GRIDS); @@ -774,6 +778,8 @@ static void sculpt_gesture_init_face_set_properties(SculptGestureContext *sgcont struct Mesh *mesh = BKE_mesh_from_object(sgcontext->vc.obact); sgcontext->operation = MEM_callocN(sizeof(SculptGestureFaceSetOperation), "Face Set Operation"); + sgcontext->ss->face_sets = BKE_sculpt_face_sets_ensure(mesh); + SculptGestureFaceSetOperation *face_set_operation = (SculptGestureFaceSetOperation *) sgcontext->operation; @@ -817,7 +823,7 @@ static void mask_gesture_apply_task_cb(void *__restrict userdata, BKE_pbvh_vertex_iter_begin (sgcontext->ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { if (sculpt_gesture_is_vertex_effected(sgcontext, &vd)) { - float prevmask = *vd.mask; + float prevmask = vd.mask ? *vd.mask : 0.0f; if (!any_masked) { any_masked = true; @@ -863,6 +869,10 @@ static void sculpt_gesture_init_mask_properties(SculptGestureContext *sgcontext, SculptGestureMaskOperation *mask_operation = (SculptGestureMaskOperation *)sgcontext->operation; + Object *object = sgcontext->vc.obact; + MultiresModifierData *mmd = BKE_sculpt_multires_active(sgcontext->vc.scene, object); + BKE_sculpt_mask_layers_ensure(sgcontext->vc.obact, mmd); + mask_operation->op.sculpt_gesture_begin = sculpt_gesture_mask_begin; mask_operation->op.sculpt_gesture_apply_for_symmetry_pass = sculpt_gesture_mask_apply_for_symmetry_pass; diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 9b6ddcd4b6d..31f3ccd2175 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -253,11 +253,11 @@ float SCULPT_vertex_mask_get(SculptSession *ss, PBVHVertRef vertex) float *mask; switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: - return ss->vmask[vertex.i]; + return ss->vmask ? ss->vmask[vertex.i] : 0.0f; case PBVH_BMESH: v = (BMVert *)vertex.i; mask = BM_ELEM_CD_GET_VOID_P(v, CustomData_get_offset(&ss->bm->vdata, CD_PAINT_MASK)); - return *mask; + return mask ? *mask : 0.0f; case PBVH_GRIDS: { const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); const int grid_index = vertex.i / key->grid_area; @@ -329,8 +329,14 @@ int SCULPT_active_face_set_get(SculptSession *ss) { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: + if (!ss->face_sets) { + return SCULPT_FACE_SET_NONE; + } return ss->face_sets[ss->active_face_index]; case PBVH_GRIDS: { + if (!ss->face_sets) { + return SCULPT_FACE_SET_NONE; + } const int face_index = BKE_subdiv_ccg_grid_to_face_index(ss->subdiv_ccg, ss->active_grid_index); return ss->face_sets[face_index]; @@ -383,6 +389,7 @@ 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); switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: case PBVH_GRIDS: @@ -405,6 +412,7 @@ void SCULPT_face_set_visibility_set(SculptSession *ss, int face_set, bool visibl void SCULPT_face_sets_visibility_invert(SculptSession *ss) { + BLI_assert(ss->face_sets != NULL); switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: case PBVH_GRIDS: @@ -422,6 +430,9 @@ void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible) switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: case PBVH_GRIDS: + if (!ss->face_sets) { + return; + } for (int i = 0; i < ss->totfaces; i++) { /* This can run on geometry without a face set assigned, so its ID sign can't be changed to @@ -446,11 +457,15 @@ void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible) bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, PBVHVertRef vertex) { + const bool *hide_poly = BKE_pbvh_get_poly_hide(ss->pbvh); + if (!hide_poly) { + return true; + } switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: { MeshElemMap *vert_map = &ss->pmap[vertex.i]; for (int j = 0; j < ss->pmap[vertex.i].count; j++) { - if (ss->face_sets[vert_map->indices[j]] > 0) { + if (!hide_poly[vert_map->indices[j]]) { return true; } } @@ -466,11 +481,15 @@ bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, PBVHVertRef verte bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, PBVHVertRef vertex) { + const bool *hide_poly = BKE_pbvh_get_poly_hide(ss->pbvh); + if (!hide_poly) { + return true; + } switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: { MeshElemMap *vert_map = &ss->pmap[vertex.i]; for (int j = 0; j < ss->pmap[vertex.i].count; j++) { - if (ss->face_sets[vert_map->indices[j]] < 0) { + if (hide_poly[vert_map->indices[j]]) { return false; } } @@ -482,7 +501,7 @@ bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, PBVHVertRe 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); - return ss->face_sets[face_index] > 0; + return !hide_poly[face_index]; } } return true; @@ -492,6 +511,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); MeshElemMap *vert_map = &ss->pmap[vertex.i]; for (int j = 0; j < ss->pmap[vertex.i].count; j++) { if (ss->face_sets[vert_map->indices[j]] > 0) { @@ -502,6 +522,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); 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); @@ -517,6 +538,9 @@ int SCULPT_vertex_face_set_get(SculptSession *ss, PBVHVertRef vertex) { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: { + if (!ss->face_sets) { + return SCULPT_FACE_SET_NONE; + } MeshElemMap *vert_map = &ss->pmap[vertex.i]; int face_set = 0; for (int i = 0; i < ss->pmap[vertex.i].count; i++) { @@ -529,6 +553,9 @@ int SCULPT_vertex_face_set_get(SculptSession *ss, PBVHVertRef vertex) case PBVH_BMESH: return 0; case PBVH_GRIDS: { + if (!ss->face_sets) { + return SCULPT_FACE_SET_NONE; + } 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); @@ -542,6 +569,9 @@ bool SCULPT_vertex_has_face_set(SculptSession *ss, PBVHVertRef vertex, int face_ { switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: { + if (!ss->face_sets) { + return face_set == SCULPT_FACE_SET_NONE; + } MeshElemMap *vert_map = &ss->pmap[vertex.i]; for (int i = 0; i < ss->pmap[vertex.i].count; i++) { if (ss->face_sets[vert_map->indices[i]] == face_set) { @@ -553,6 +583,9 @@ bool SCULPT_vertex_has_face_set(SculptSession *ss, PBVHVertRef vertex, int face_ case PBVH_BMESH: return true; case PBVH_GRIDS: { + if (!ss->face_sets) { + return face_set == SCULPT_FACE_SET_NONE; + } 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); @@ -599,6 +632,9 @@ static void UNUSED_FUNCTION(sculpt_visibility_sync_vertex_to_face_sets)(SculptSe void SCULPT_visibility_sync_all_vertex_to_face_sets(SculptSession *ss) { if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) { + if (ss->face_sets == NULL) { + return; + } for (int i = 0; i < ss->totfaces; i++) { const MPoly *poly = &ss->mpoly[i]; bool poly_visible = true; @@ -620,6 +656,9 @@ void SCULPT_visibility_sync_all_vertex_to_face_sets(SculptSession *ss) static bool sculpt_check_unique_face_set_in_base_mesh(SculptSession *ss, int index) { + if (!ss->face_sets) { + return true; + } MeshElemMap *vert_map = &ss->pmap[index]; int face_set = -1; for (int i = 0; i < ss->pmap[index].count; i++) { @@ -676,6 +715,9 @@ bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, PBVHVertRef vertex) case PBVH_BMESH: return true; case PBVH_GRIDS: { + if (!ss->face_sets) { + return true; + } 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; @@ -703,6 +745,9 @@ int SCULPT_face_set_next_available_get(SculptSession *ss) switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: case PBVH_GRIDS: { + if (!ss->face_sets) { + return 0; + } int next_face_set = 0; for (int i = 0; i < ss->totfaces; i++) { if (abs(ss->face_sets[i]) > next_face_set) { @@ -792,9 +837,10 @@ static void sculpt_vertex_neighbors_get_faces(SculptSession *ss, iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY; iter->neighbors = iter->neighbors_fixed; iter->neighbor_indices = iter->neighbor_indices_fixed; + const bool *hide_poly = BKE_pbvh_get_vert_hide(ss->pbvh); for (int i = 0; i < ss->pmap[vertex.i].count; i++) { - if (ss->face_sets[vert_map->indices[i]] < 0) { + if (hide_poly && hide_poly[vert_map->indices[i]]) { /* Skip connectivity from hidden faces. */ continue; } @@ -3297,6 +3343,15 @@ static void do_brush_action(Sculpt *sd, BKE_pbvh_ensure_node_loops(ss->pbvh); } + if (SCULPT_tool_is_mask(brush->sculpt_tool)) { + MultiresModifierData *mmd = BKE_sculpt_multires_active(ss->scene, ob); + BKE_sculpt_mask_layers_ensure(ob, mmd); + } + if (SCULPT_tool_is_face_sets(brush->sculpt_tool)) { + Mesh *mesh = BKE_object_get_original_mesh(ob); + ss->face_sets = BKE_sculpt_face_sets_ensure(mesh); + } + /* Build a list of all nodes that are potentially within the brush's area of influence */ if (SCULPT_tool_needs_all_pbvh_nodes(brush)) { diff --git a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c index 8b7b26b127d..2f5a1baa866 100644 --- a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c +++ b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c @@ -215,13 +215,7 @@ static void SCULPT_dynamic_topology_disable_ex( BKE_sculptsession_bm_to_me(ob, true); /* Reset Face Sets as they are no longer valid. */ - if (!CustomData_has_layer(&me->pdata, CD_SCULPT_FACE_SETS)) { - CustomData_add_layer(&me->pdata, CD_SCULPT_FACE_SETS, CD_SET_DEFAULT, NULL, me->totpoly); - } - ss->face_sets = CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS); - for (int i = 0; i < me->totpoly; i++) { - ss->face_sets[i] = 1; - } + CustomData_free_layers(&me->pdata, CD_SCULPT_FACE_SETS, me->totpoly); me->face_sets_color_default = 1; /* Sync the visibility to vertices manually as the pmap is still not initialized. */ diff --git a/source/blender/editors/sculpt_paint/sculpt_expand.c b/source/blender/editors/sculpt_paint/sculpt_expand.c index 4aafeacfbff..414a855ab2f 100644 --- a/source/blender/editors/sculpt_paint/sculpt_expand.c +++ b/source/blender/editors/sculpt_paint/sculpt_expand.c @@ -17,6 +17,7 @@ #include "DNA_brush_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "BKE_brush.h" @@ -1390,9 +1391,15 @@ static void sculpt_expand_original_state_store(Object *ob, ExpandCache *expand_c /* Face Sets are always stored as they are needed for snapping. */ expand_cache->initial_face_sets = MEM_malloc_arrayN(totface, sizeof(int), "initial face set"); expand_cache->original_face_sets = MEM_malloc_arrayN(totface, sizeof(int), "original face set"); - for (int i = 0; i < totface; i++) { - expand_cache->initial_face_sets[i] = ss->face_sets[i]; - expand_cache->original_face_sets[i] = ss->face_sets[i]; + if (ss->face_sets) { + for (int i = 0; i < totface; i++) { + expand_cache->initial_face_sets[i] = ss->face_sets[i]; + expand_cache->original_face_sets[i] = ss->face_sets[i]; + } + } + else { + memset(expand_cache->initial_face_sets, SCULPT_FACE_SET_NONE, sizeof(int) * totface); + memset(expand_cache->original_face_sets, SCULPT_FACE_SET_NONE, sizeof(int) * totface); } if (expand_cache->target == SCULPT_EXPAND_TARGET_MASK) { @@ -2118,6 +2125,16 @@ static int sculpt_expand_invoke(bContext *C, wmOperator *op, const wmEvent *even return OPERATOR_CANCELLED; } + if (ss->expand_cache->target == SCULPT_EXPAND_TARGET_FACE_SETS) { + Mesh *mesh = ob->data; + ss->face_sets = BKE_sculpt_face_sets_ensure(mesh); + } + + if (ss->expand_cache->target == SCULPT_EXPAND_TARGET_MASK) { + MultiresModifierData *mmd = BKE_sculpt_multires_active(ss->scene, ob); + BKE_sculpt_mask_layers_ensure(ob, mmd); + } + /* Face Set operations are not supported in dyntopo. */ if (ss->expand_cache->target == SCULPT_EXPAND_TARGET_FACE_SETS && BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) { diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c index 3c724915102..d2030aa5505 100644 --- a/source/blender/editors/sculpt_paint/sculpt_face_set.c +++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c @@ -303,6 +303,9 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } + Mesh *mesh = ob->data; + ss->face_sets = BKE_sculpt_face_sets_ensure(mesh); + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, mode == SCULPT_FACE_SET_MASKED, false); const int tot_vert = SCULPT_vertex_count_get(ss); @@ -349,7 +352,6 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op) } if (all_visible) { - Mesh *mesh = ob->data; mesh->face_sets_color_default = next_face_set; BKE_pbvh_face_sets_color_set( ss->pbvh, mesh->face_sets_color_seed, mesh->face_sets_color_default); @@ -373,7 +375,6 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op) } if (mode == SCULPT_FACE_SET_SELECTION) { - Mesh *mesh = ob->data; BMesh *bm; const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh); bm = BM_mesh_create(&allocsize, @@ -850,6 +851,10 @@ static int sculpt_face_sets_change_visibility_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } + if (!pbvh_has_face_sets(ss->pbvh)) { + return OPERATOR_CANCELLED; + } + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); const int tot_vert = SCULPT_vertex_count_get(ss); @@ -1000,6 +1005,10 @@ static int sculpt_face_sets_randomize_colors_exec(bContext *C, wmOperator *UNUSE return OPERATOR_CANCELLED; } + if (!pbvh_has_face_sets(ss->pbvh)) { + return OPERATOR_CANCELLED; + } + PBVH *pbvh = ob->sculpt->pbvh; PBVHNode **nodes; int totnode; @@ -1154,7 +1163,9 @@ static void sculpt_face_set_shrink(Object *ob, static bool check_single_face_set(SculptSession *ss, int *face_sets, const bool check_visible_only) { - + if (face_sets == NULL) { + return true; + } int first_face_set = SCULPT_FACE_SET_NONE; if (check_visible_only) { for (int f = 0; f < ss->totfaces; f++) { diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c index cba1d3dcdc1..bb27e4f1e9e 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c @@ -14,6 +14,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" #include "BKE_brush.h" #include "BKE_context.h" @@ -174,11 +175,15 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_active_object(C); Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); + const Scene *scene = CTX_data_scene(C); PBVHNode **nodes; Sculpt *sd = CTX_data_tool_settings(C)->sculpt; int totnode; int filter_type = RNA_enum_get(op->ptr, "filter_type"); + MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob); + BKE_sculpt_mask_layers_ensure(ob, mmd); + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); SculptSession *ss = ob->sculpt; diff --git a/source/blender/editors/sculpt_paint/sculpt_geodesic.c b/source/blender/editors/sculpt_paint/sculpt_geodesic.c index 7f6da27ddcf..6f813c9920e 100644 --- a/source/blender/editors/sculpt_paint/sculpt_geodesic.c +++ b/source/blender/editors/sculpt_paint/sculpt_geodesic.c @@ -174,6 +174,8 @@ static float *SCULPT_geodesic_mesh_create(Object *ob, } } + const bool *hide_poly = BKE_pbvh_get_poly_hide(ss->pbvh); + /* Add edges adjacent to an initial vertex to the queue. */ for (int i = 0; i < totedge; i++) { const int v1 = edges[i].v1; @@ -203,7 +205,7 @@ static float *SCULPT_geodesic_mesh_create(Object *ob, if (ss->epmap[e].count != 0) { for (int poly_map_index = 0; poly_map_index < ss->epmap[e].count; poly_map_index++) { const int poly = ss->epmap[e].indices[poly_map_index]; - if (ss->face_sets[poly] <= 0) { + if (hide_poly && hide_poly[poly]) { continue; } const MPoly *mpoly = &polys[poly]; diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index cf901d7cf36..607e0fc3ef6 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -1837,6 +1837,16 @@ BLI_INLINE bool SCULPT_tool_is_paint(int tool) return ELEM(tool, SCULPT_TOOL_PAINT, SCULPT_TOOL_SMEAR); } +BLI_INLINE bool SCULPT_tool_is_mask(int tool) +{ + return ELEM(tool, SCULPT_TOOL_MASK); +} + +BLI_INLINE bool SCULPT_tool_is_face_sets(int tool) +{ + return ELEM(tool, SCULPT_TOOL_DRAW_FACE_SETS); +} + #ifdef __cplusplus } #endif diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c index 9556d24f12c..ec246cd3788 100644 --- a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c +++ b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c @@ -391,7 +391,7 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent if (create_face_set) { ss->filter_cache->prev_face_set = MEM_callocN(sizeof(float) * ss->totfaces, "prev face mask"); for (int i = 0; i < ss->totfaces; i++) { - ss->filter_cache->prev_face_set[i] = ss->face_sets[i]; + ss->filter_cache->prev_face_set[i] = ss->face_sets ? ss->face_sets[i] : 0; } ss->filter_cache->new_face_set = SCULPT_face_set_next_available_get(ss); } diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.c b/source/blender/editors/sculpt_paint/sculpt_ops.c index 10a2ece73de..055e02a5703 100644 --- a/source/blender/editors/sculpt_paint/sculpt_ops.c +++ b/source/blender/editors/sculpt_paint/sculpt_ops.c @@ -300,28 +300,30 @@ static void sculpt_init_session(Main *bmain, Depsgraph *depsgraph, Scene *scene, ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session"); ob->sculpt->mode_type = OB_MODE_SCULPT; - BKE_sculpt_ensure_orig_mesh_data(scene, ob); + BKE_sculpt_ensure_orig_mesh_data(ob); BKE_scene_graph_evaluated_ensure(depsgraph, bmain); /* This function expects a fully evaluated depsgraph. */ BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false); - /* Here we can detect geometry that was just added to Sculpt Mode as it has the - * SCULPT_FACE_SET_NONE assigned, so we can create a new Face Set for it. */ - /* In sculpt mode all geometry that is assigned to SCULPT_FACE_SET_NONE is considered as not - * initialized, which is used is some operators that modify the mesh topology to perform certain - * actions in the new polys. After these operations are finished, all polys should have a valid - * face set ID assigned (different from SCULPT_FACE_SET_NONE) to manage their visibility - * correctly. */ - /* TODO(pablodp606): Based on this we can improve the UX in future tools for creating new - * objects, like moving the transform pivot position to the new area or masking existing - * geometry. */ SculptSession *ss = ob->sculpt; - const int new_face_set = SCULPT_face_set_next_available_get(ss); - for (int i = 0; i < ss->totfaces; i++) { - if (ss->face_sets[i] == SCULPT_FACE_SET_NONE) { - ss->face_sets[i] = new_face_set; + if (ss->face_sets) { + /* Here we can detect geometry that was just added to Sculpt Mode as it has the + * SCULPT_FACE_SET_NONE assigned, so we can create a new Face Set for it. */ + /* In sculpt mode all geometry that is assigned to SCULPT_FACE_SET_NONE is considered as not + * initialized, which is used is some operators that modify the mesh topology to perform + * certain actions in the new polys. After these operations are finished, all polys should have + * a valid face set ID assigned (different from SCULPT_FACE_SET_NONE) to manage their + * visibility correctly. */ + /* TODO(pablodp606): Based on this we can improve the UX in future tools for creating new + * objects, like moving the transform pivot position to the new area or masking existing + * geometry. */ + const int new_face_set = SCULPT_face_set_next_available_get(ss); + for (int i = 0; i < ss->totfaces; i++) { + if (ss->face_sets[i] == SCULPT_FACE_SET_NONE) { + ss->face_sets[i] = new_face_set; + } } } } diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index fb8e2ae91b6..54ae6d84df7 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -474,9 +474,10 @@ static bool sculpt_undo_restore_face_sets(bContext *C, SculptUndoNode *unode) ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob = BKE_view_layer_active_object_get(view_layer); Mesh *me = BKE_object_get_original_mesh(ob); - int *face_sets = CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS); + int *face_sets = CustomData_add_layer( + &me->pdata, CD_SCULPT_FACE_SETS, CD_CONSTRUCT, NULL, me->totpoly); for (int i = 0; i < me->totpoly; i++) { - face_sets[i] = unode->face_sets[i]; + SWAP(int, face_sets[i], unode->face_sets[i]); } return false; } @@ -1350,8 +1351,13 @@ static SculptUndoNode *sculpt_undo_face_sets_push(Object *ob, SculptUndoType typ unode->face_sets = MEM_callocN(me->totpoly * sizeof(int), "sculpt face sets"); const int *face_sets = CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS); - for (int i = 0; i < me->totpoly; i++) { - unode->face_sets[i] = face_sets[i]; + if (face_sets) { + for (int i = 0; i < me->totpoly; i++) { + unode->face_sets[i] = face_sets[i]; + } + } + else { + memset(unode->face_sets, SCULPT_FACE_SET_NONE, sizeof(int) * me->totpoly); } BLI_addtail(&usculpt->nodes, unode); @@ -1509,7 +1515,9 @@ SculptUndoNode *SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType sculpt_undo_store_hidden(ob, unode); break; case SCULPT_UNDO_MASK: - sculpt_undo_store_mask(ob, unode); + if (pbvh_has_mask(ss->pbvh)) { + sculpt_undo_store_mask(ob, unode); + } break; case SCULPT_UNDO_COLOR: sculpt_undo_store_color(ob, unode); diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c index 8b9776cf94d..4739fa52674 100644 --- a/source/blender/editors/sculpt_paint/sculpt_uv.c +++ b/source/blender/editors/sculpt_paint/sculpt_uv.c @@ -686,9 +686,10 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm /* Winding was added to island detection in 5197aa04c6bd * However the sculpt tools can flip faces, potentially creating orphaned islands. * See T100132 */ - bool use_winding = false; + const bool use_winding = false; + const bool use_seams = true; data->elementMap = BM_uv_element_map_create( - bm, scene, false, use_winding, do_island_optimization); + bm, scene, false, use_winding, use_seams, do_island_optimization); if (!data->elementMap) { uv_sculpt_stroke_exit(C, op); diff --git a/source/blender/editors/space_image/image_undo.cc b/source/blender/editors/space_image/image_undo.cc index 065641c4051..8f144264824 100644 --- a/source/blender/editors/space_image/image_undo.cc +++ b/source/blender/editors/space_image/image_undo.cc @@ -522,7 +522,7 @@ static void ubuf_ensure_compat_ibuf(const UndoImageBuf *ubuf, ImBuf *ibuf) IMB_rect_size_set(ibuf, ubuf->image_dims); if (ubuf->image_state.use_float) { - imb_addrectfloatImBuf(ibuf); + imb_addrectfloatImBuf(ibuf, 4); } else { imb_addrectImBuf(ibuf); diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c index 801d032a861..bcdbbb00d1c 100644 --- a/source/blender/editors/space_nla/nla_edit.c +++ b/source/blender/editors/space_nla/nla_edit.c @@ -606,6 +606,36 @@ void NLA_OT_view_frame(wmOperatorType *ot) * (or the active block if no space in the track). * \{ */ +/* Get a list of the editable tracks being shown in the NLA. */ +static int nlaedit_get_editable_tracks(bAnimContext *ac, ListBase *anim_data) +{ + const int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ACTIVE | ANIMFILTER_FOREDIT | + ANIMFILTER_FCURVESONLY); + return ANIM_animdata_filter(ac, anim_data, filter, ac->data, ac->datatype); +} + +static int nlaedit_add_actionclip_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + /* Get editor data. */ + bAnimContext ac; + if (ANIM_animdata_get_context(C, &ac) == 0) { + return OPERATOR_CANCELLED; + } + + ListBase anim_data = {NULL, NULL}; + const size_t items = nlaedit_get_editable_tracks(&ac, &anim_data); + + if (items == 0) { + BKE_report(op->reports, + RPT_ERROR, + "No active track(s) to add strip to, select an existing track or add one before " + "trying again"); + return OPERATOR_CANCELLED; + } + + return WM_enum_search_invoke(C, op, event); +} + /* add the specified action as new strip */ static int nlaedit_add_actionclip_exec(bContext *C, wmOperator *op) { @@ -615,8 +645,6 @@ static int nlaedit_add_actionclip_exec(bContext *C, wmOperator *op) ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; - size_t items; - int filter; bAction *act; @@ -654,20 +682,7 @@ static int nlaedit_add_actionclip_exec(bContext *C, wmOperator *op) */ nlaedit_add_tracks_empty(&ac); - /* get a list of the editable tracks being shown in the NLA - * - this is limited to active ones for now, but could be expanded to - */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ACTIVE | ANIMFILTER_FOREDIT | - ANIMFILTER_FCURVESONLY); - items = ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); - - if (items == 0) { - BKE_report(op->reports, - RPT_ERROR, - "No active track(s) to add strip to, select an existing track or add one before " - "trying again"); - return OPERATOR_CANCELLED; - } + nlaedit_get_editable_tracks(&ac, &anim_data); /* for every active track, * try to add strip to free space in track or to the top of the stack if no space */ @@ -736,7 +751,7 @@ void NLA_OT_actionclip_add(wmOperatorType *ot) "Add an Action-Clip strip (i.e. an NLA Strip referencing an Action) to the active track"; /* api callbacks */ - ot->invoke = WM_enum_search_invoke; + ot->invoke = nlaedit_add_actionclip_invoke; ot->exec = nlaedit_add_actionclip_exec; ot->poll = nlaop_poll_tweakmode_off; diff --git a/source/blender/editors/space_node/link_drag_search.cc b/source/blender/editors/space_node/link_drag_search.cc index a4be0a65230..f1387da97b5 100644 --- a/source/blender/editors/space_node/link_drag_search.cc +++ b/source/blender/editors/space_node/link_drag_search.cc @@ -227,12 +227,10 @@ static void link_drag_search_exec_fn(bContext *C, void *arg1, void *arg2) ED_node_tree_propagate_change(C, &bmain, snode.edittree); /* Start translation operator with the new node. */ - wmOperatorType *ot = WM_operatortype_find("NODE_OT_translate_attach", true); + wmOperatorType *ot = WM_operatortype_find("NODE_OT_translate_attach_remove_on_cancel", true); BLI_assert(ot); PointerRNA ptr; WM_operator_properties_create_ptr(&ptr, ot); - RNA_boolean_set(&ptr, "view2d_edge_pan", true); - RNA_boolean_set(&ptr, "remove_on_cancel", true); WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr, nullptr); WM_operator_properties_free(&ptr); } diff --git a/source/blender/editors/space_node/node_ops.cc b/source/blender/editors/space_node/node_ops.cc index 3b3189983e2..a208370a6f9 100644 --- a/source/blender/editors/space_node/node_ops.cc +++ b/source/blender/editors/space_node/node_ops.cc @@ -144,7 +144,7 @@ void ED_operatormacros_node() WM_operatortype_macro_define(ot, "NODE_OT_attach"); WM_operatortype_macro_define(ot, "NODE_OT_insert_offset"); - /* NODE_OT_translate_attach with remove_on_canel set to true */ + /* NODE_OT_translate_attach with remove_on_cancel set to true. */ ot = WM_operatortype_append_macro("NODE_OT_translate_attach_remove_on_cancel", "Move and Attach", "Move nodes and attach to frame", diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc index 7dbaa8ccd6d..929fb64bd70 100644 --- a/source/blender/editors/space_node/node_relationships.cc +++ b/source/blender/editors/space_node/node_relationships.cc @@ -1727,32 +1727,34 @@ static int node_attach_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent SpaceNode &snode = *CTX_wm_space_node(C); bNodeTree &ntree = *snode.edittree; bNode *frame = node_find_frame_to_attach(region, ntree, event->mval); + if (frame == nullptr) { + /* Return "finished" so that auto offset operator macros can work. */ + return OPERATOR_FINISHED; + } - if (frame) { - LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree.nodes) { - if (node->flag & NODE_SELECT) { - if (node->parent == nullptr) { - /* disallow moving a parent into its child */ - if (nodeAttachNodeCheck(frame, node) == false) { - /* attach all unparented nodes */ - nodeAttachNode(node, frame); - } + LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree.nodes) { + if (node->flag & NODE_SELECT) { + if (node->parent == nullptr) { + /* disallow moving a parent into its child */ + if (nodeAttachNodeCheck(frame, node) == false) { + /* attach all unparented nodes */ + nodeAttachNode(node, frame); } - else { - /* attach nodes which share parent with the frame */ - bNode *parent; - for (parent = frame->parent; parent; parent = parent->parent) { - if (parent == node->parent) { - break; - } + } + else { + /* attach nodes which share parent with the frame */ + bNode *parent; + for (parent = frame->parent; parent; parent = parent->parent) { + if (parent == node->parent) { + break; } + } - if (parent) { - /* disallow moving a parent into its child */ - if (nodeAttachNodeCheck(frame, node) == false) { - nodeDetachNode(node); - nodeAttachNode(node, frame); - } + if (parent) { + /* disallow moving a parent into its child */ + if (nodeAttachNodeCheck(frame, node) == false) { + nodeDetachNode(node); + nodeAttachNode(node, frame); } } } diff --git a/source/blender/editors/space_node/node_select.cc b/source/blender/editors/space_node/node_select.cc index 1f1ce9c0c2b..d93b205b1b7 100644 --- a/source/blender/editors/space_node/node_select.cc +++ b/source/blender/editors/space_node/node_select.cc @@ -644,28 +644,29 @@ static bool node_mouse_select(bContext *C, } } - /* update node order */ - if (changed || found) { - bool active_texture_changed = false; - bool viewer_node_changed = false; - if ((node != nullptr) && (node_was_selected == false || params->select_passthrough == false)) { - viewer_node_changed = (node->flag & NODE_DO_OUTPUT) == 0 && node->type == GEO_NODE_VIEWER; - ED_node_set_active(&bmain, &snode, snode.edittree, node, &active_texture_changed); - } - else if (node != nullptr && node->type == GEO_NODE_VIEWER) { - ED_spreadsheet_context_paths_set_geometry_node(&bmain, &snode, node); - } - ED_node_set_active_viewer_key(&snode); - node_sort(*snode.edittree); - if ((active_texture_changed && has_workbench_in_texture_color(wm, scene, ob)) || - viewer_node_changed) { - DEG_id_tag_update(&snode.edittree->id, ID_RECALC_COPY_ON_WRITE); - } + if (!(changed || found)) { + return false; + } - WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr); + bool active_texture_changed = false; + bool viewer_node_changed = false; + if ((node != nullptr) && (node_was_selected == false || params->select_passthrough == false)) { + viewer_node_changed = (node->flag & NODE_DO_OUTPUT) == 0 && node->type == GEO_NODE_VIEWER; + ED_node_set_active(&bmain, &snode, snode.edittree, node, &active_texture_changed); } + else if (node != nullptr && node->type == GEO_NODE_VIEWER) { + ED_spreadsheet_context_paths_set_geometry_node(&bmain, &snode, node); + } + ED_node_set_active_viewer_key(&snode); + node_sort(*snode.edittree); + if ((active_texture_changed && has_workbench_in_texture_color(wm, scene, ob)) || + viewer_node_changed) { + DEG_id_tag_update(&snode.edittree->id, ID_RECALC_COPY_ON_WRITE); + } + + WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr); - return changed || found; + return true; } static int node_select_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/transform/transform_convert_action.c b/source/blender/editors/transform/transform_convert_action.c index 252f150995e..83e47d9acc0 100644 --- a/source/blender/editors/transform/transform_convert_action.c +++ b/source/blender/editors/transform/transform_convert_action.c @@ -902,18 +902,18 @@ static void special_aftertrans_update__actedit(bContext *C, TransInfo *t) if (ELEM(t->frame_side, 'L', 'R')) { /* TFM_TIME_EXTEND */ /* same as below */ ED_markers_post_apply_transform( - ED_context_get_markers(C), t->scene, t->mode, t->values[0], t->frame_side); + ED_context_get_markers(C), t->scene, t->mode, t->values_final[0], t->frame_side); } else /* TFM_TIME_TRANSLATE */ #endif { ED_markers_post_apply_transform( - ED_context_get_markers(C), t->scene, t->mode, t->values[0], t->frame_side); + ED_context_get_markers(C), t->scene, t->mode, t->values_final[0], t->frame_side); } } else if (t->mode == TFM_TIME_SCALE) { ED_markers_post_apply_transform( - ED_context_get_markers(C), t->scene, t->mode, t->values[0], t->frame_side); + ED_context_get_markers(C), t->scene, t->mode, t->values_final[0], t->frame_side); } } diff --git a/source/blender/editors/transform/transform_convert_mesh_uv.c b/source/blender/editors/transform/transform_convert_mesh_uv.c index f3bef2c283b..27f12137e3a 100644 --- a/source/blender/editors/transform/transform_convert_mesh_uv.c +++ b/source/blender/editors/transform/transform_convert_mesh_uv.c @@ -265,7 +265,7 @@ static void createTransUVs(bContext *C, TransInfo *t) /* count */ if (is_island_center) { /* create element map with island information */ - elementmap = BM_uv_element_map_create(em->bm, scene, true, false, true); + elementmap = BM_uv_element_map_create(em->bm, scene, true, false, true, true); if (elementmap == NULL) { continue; } diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c index eefc9d0cc2a..ddc99caeef5 100644 --- a/source/blender/editors/transform/transform_convert_sequencer.c +++ b/source/blender/editors/transform/transform_convert_sequencer.c @@ -708,12 +708,12 @@ static void special_aftertrans_update__sequencer(bContext *UNUSED(C), TransInfo if (t->mode == TFM_SEQ_SLIDE) { if (t->frame_side == 'B') { ED_markers_post_apply_transform( - &t->scene->markers, t->scene, TFM_TIME_TRANSLATE, t->values[0], t->frame_side); + &t->scene->markers, t->scene, TFM_TIME_TRANSLATE, t->values_final[0], t->frame_side); } } else if (ELEM(t->frame_side, 'L', 'R')) { ED_markers_post_apply_transform( - &t->scene->markers, t->scene, TFM_TIME_EXTEND, t->values[0], t->frame_side); + &t->scene->markers, t->scene, TFM_TIME_EXTEND, t->values_final[0], t->frame_side); } } } diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c index 2f268d4ae23..e70851aedd6 100644 --- a/source/blender/editors/util/ed_util.c +++ b/source/blender/editors/util/ed_util.c @@ -377,7 +377,7 @@ void unpack_menu(bContext *C, char local_name[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX]; BLI_split_file_part(abs_name, fi, sizeof(fi)); - BLI_snprintf(local_name, sizeof(local_name), "//%s/%s", folder, fi); + BLI_path_join(local_name, sizeof(local_name), "//", folder, fi, NULL); if (!STREQ(abs_name, local_name)) { switch (BKE_packedfile_compare_to_file(blendfile_path, local_name, pf)) { case PF_CMP_NOFILE: diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index c0dd7623ade..4cc2c6450df 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -535,7 +535,7 @@ static bool uvedit_uv_straighten(Scene *scene, BMesh *bm, eUVWeldAlign tool) return false; } - UvElementMap *element_map = BM_uv_element_map_create(bm, scene, true, false, true); + UvElementMap *element_map = BM_uv_element_map_create(bm, scene, true, false, true, true); if (element_map == NULL) { return false; } diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c index cecf0ff7914..43c8620df1d 100644 --- a/source/blender/editors/uvedit/uvedit_select.c +++ b/source/blender/editors/uvedit/uvedit_select.c @@ -5384,7 +5384,7 @@ static void uv_isolate_selected_islands(const Scene *scene, BLI_assert((scene->toolsettings->uv_flag & UV_SYNC_SELECTION) == 0); BMFace *efa; BMIter iter, liter; - UvElementMap *elementmap = BM_uv_element_map_create(em->bm, scene, false, false, true); + UvElementMap *elementmap = BM_uv_element_map_create(em->bm, scene, false, false, true, true); if (elementmap == NULL) { return; } diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c index e89f99fc412..e19cc67bd16 100644 --- a/source/blender/editors/uvedit/uvedit_smart_stitch.c +++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c @@ -1855,7 +1855,7 @@ static StitchState *stitch_init(bContext *C, * for stitch this isn't useful behavior, see T86924. */ const int selectmode_orig = scene->toolsettings->selectmode; scene->toolsettings->selectmode = SCE_SELECT_VERTEX; - state->element_map = BM_uv_element_map_create(state->em->bm, scene, false, true, true); + state->element_map = BM_uv_element_map_create(state->em->bm, scene, false, true, true, true); scene->toolsettings->selectmode = selectmode_orig; if (!state->element_map) { diff --git a/source/blender/geometry/intern/add_curves_on_mesh.cc b/source/blender/geometry/intern/add_curves_on_mesh.cc index 5173eaa3f1b..047f7dc7911 100644 --- a/source/blender/geometry/intern/add_curves_on_mesh.cc +++ b/source/blender/geometry/intern/add_curves_on_mesh.cc @@ -372,6 +372,28 @@ AddCurvesOnMeshOutputs add_curves_on_mesh(CurvesGeometry &curves, curves.fill_curve_types(new_curves_range, CURVE_TYPE_CATMULL_ROM); + /* Explicitly set all other attributes besides those processed above to default values. */ + bke::MutableAttributeAccessor attributes = curves.attributes_for_write(); + Set<std::string> attributes_to_skip{{"position", + "curve_type", + "surface_uv_coordinate", + ".selection_point_float", + ".selection_curve_float"}}; + attributes.for_all( + [&](const bke::AttributeIDRef &id, const bke::AttributeMetaData /*meta_data*/) { + if (id.is_named() && attributes_to_skip.contains(id.name())) { + return true; + } + bke::GSpanAttributeWriter attribute = attributes.lookup_for_write_span(id); + const int new_elements_num = attribute.domain == ATTR_DOMAIN_POINT ? new_points_num : + new_curves_num; + const CPPType &type = attribute.span.type(); + GMutableSpan new_data = attribute.span.take_back(new_elements_num); + type.fill_assign_n(type.default_value(), new_data.data(), new_data.size()); + attribute.finish(); + return true; + }); + return outputs; } diff --git a/source/blender/geometry/intern/uv_parametrizer.cc b/source/blender/geometry/intern/uv_parametrizer.cc index 4f763b09bef..f074febe23a 100644 --- a/source/blender/geometry/intern/uv_parametrizer.cc +++ b/source/blender/geometry/intern/uv_parametrizer.cc @@ -307,12 +307,70 @@ static float p_vec2_angle(const float v1[2], const float v2[2], const float v3[2 { return angle_v2v2v2(v1, v2, v3); } + +/* Angles close to 0 or 180 degrees cause rows filled with zeros in the linear_solver. + * The matrix will then be rank deficient and / or have poor conditioning. + * => Reduce the maximum angle to 179 degrees, and spread the remainder to the other angles. + */ +static void fix_large_angle(const float v_fix[3], + const float v1[3], + const float v2[3], + float *r_fix, + float *r_a1, + float *r_a2) +{ + const float max_angle = (float)M_PI * (179.0f / 180.0f); + const float fix_amount = *r_fix - max_angle; + if (fix_amount < 0.0f) { + return; /* angle is reasonable, i.e. less than 179 degrees. */ + } + + /* The triangle is probably degenerate, or close to it. + * Without loss of generality, transform the triangle such that + * v_fix == { 0, s}, *r_fix = 180 degrees + * v1 == {-x1, 0}, *r_a1 = 0 + * v2 == { x2, 0}, *r_a2 = 0 + * + * With `s = 0`, `x1 > 0`, `x2 > 0` + * + * Now make `s` a small number and do some math: + * tan(*r_a1) = s / x1 + * tan(*r_a2) = s / x2 + * + * Remember that `tan = sin / cos`, `sin(s) ~= s` and `cos(s) = 1` + * + * Rearrange to obtain: + * *r_a1 = fix_amount * x2 / (x1 + x2) + * *r_a2 = fix_amount * x1 / (x1 + x2) + */ + + const float dist_v1 = len_v3v3(v_fix, v1); + const float dist_v2 = len_v3v3(v_fix, v2); + const float sum = dist_v1 + dist_v2; + const float weight = (sum > 1e-20f) ? dist_v2 / sum : 0.5f; + + /* Ensure sum of angles in triangle is unchanged. */ + *r_fix -= fix_amount; + *r_a1 += fix_amount * weight; + *r_a2 += fix_amount * (1.0f - weight); +} + static void p_triangle_angles( const float v1[3], const float v2[3], const float v3[3], float *r_a1, float *r_a2, float *r_a3) { *r_a1 = p_vec_angle(v3, v1, v2); *r_a2 = p_vec_angle(v1, v2, v3); - *r_a3 = (float)M_PI - *r_a2 - *r_a1; + *r_a3 = p_vec_angle(v2, v3, v1); + + /* Fix for degenerate geometry e.g. v1 = sum(v2 + v3). See T100874 */ + fix_large_angle(v1, v2, v3, r_a1, r_a2, r_a3); + fix_large_angle(v2, v3, v1, r_a2, r_a3, r_a1); + fix_large_angle(v3, v1, v2, r_a3, r_a1, r_a2); + + /* Workaround for degenerate geometry, e.g. v1 == v2 == v3. */ + *r_a1 = max_ff(*r_a1, 0.001f); + *r_a2 = max_ff(*r_a2, 0.001f); + *r_a3 = max_ff(*r_a3, 0.001f); } static void p_face_angles(PFace *f, float *r_a1, float *r_a2, float *r_a3) @@ -2266,7 +2324,6 @@ using PAbfSystem = struct PAbfSystem { float *bAlpha, *bTriangle, *bInterior; float *lambdaTriangle, *lambdaPlanar, *lambdaLength; float (*J2dt)[3], *bstar, *dstar; - float minangle, maxangle; }; static void p_abf_setup_system(PAbfSystem *sys) @@ -2294,9 +2351,6 @@ static void p_abf_setup_system(PAbfSystem *sys) for (i = 0; i < sys->ninterior; i++) { sys->lambdaLength[i] = 1.0; } - - sys->minangle = 1.0 * M_PI / 180.0; - sys->maxangle = (float)M_PI - sys->minangle; } static void p_abf_free_system(PAbfSystem *sys) @@ -2707,25 +2761,6 @@ static bool p_chart_abf_solve(PChart *chart) e3 = e2->next; p_face_angles(f, &a1, &a2, &a3); - if (a1 < sys.minangle) { - a1 = sys.minangle; - } - else if (a1 > sys.maxangle) { - a1 = sys.maxangle; - } - if (a2 < sys.minangle) { - a2 = sys.minangle; - } - else if (a2 > sys.maxangle) { - a2 = sys.maxangle; - } - if (a3 < sys.minangle) { - a3 = sys.minangle; - } - else if (a3 > sys.maxangle) { - a3 = sys.maxangle; - } - sys.alpha[e1->u.id] = sys.beta[e1->u.id] = a1; sys.alpha[e2->u.id] = sys.beta[e2->u.id] = a2; sys.alpha[e3->u.id] = sys.beta[e3->u.id] = a3; diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h index 7af4f968942..74ce4806c3d 100644 --- a/source/blender/gpu/GPU_buffers.h +++ b/source/blender/gpu/GPU_buffers.h @@ -49,7 +49,6 @@ typedef struct GPU_PBVH_Buffers GPU_PBVH_Buffers; */ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const struct Mesh *mesh, const struct MLoopTri *looptri, - const int *sculpt_face_sets, const int *face_indices, int face_indices_len); diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index 8a8c2ba3efe..e82a3833414 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -210,13 +210,9 @@ static void gpu_pbvh_batch_init(GPU_PBVH_Buffers *buffers, GPUPrimType prim) /** \name Mesh PBVH * \{ */ -static bool gpu_pbvh_is_looptri_visible(const MLoopTri *lt, - const bool *hide_vert, - const MLoop *mloop, - const int *sculpt_face_sets) +static bool gpu_pbvh_is_looptri_visible(const MLoopTri *lt, const bool *hide_poly) { - return (!paint_is_face_hidden(lt, hide_vert, mloop) && sculpt_face_sets && - sculpt_face_sets[lt->poly] > SCULPT_FACE_SET_NONE); + return !paint_is_face_hidden(lt, hide_poly); } void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id, @@ -233,8 +229,8 @@ void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id, GPUAttrRef vcol_refs[MAX_GPU_ATTR]; GPUAttrRef cd_uvs[MAX_GPU_ATTR]; - const bool *hide_vert = (const bool *)CustomData_get_layer_named( - &mesh->vdata, CD_PROP_BOOL, ".hide_vert"); + const bool *hide_poly = (const bool *)CustomData_get_layer_named( + &mesh->pdata, CD_PROP_BOOL, ".hide_poly"); const int *material_indices = (const int *)CustomData_get_layer_named( &mesh->pdata, CD_PROP_INT32, "material_index"); @@ -315,7 +311,7 @@ void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id, for (uint i = 0; i < buffers->face_indices_len; i++) { const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]]; - if (!gpu_pbvh_is_looptri_visible(lt, hide_vert, buffers->mloop, sculpt_face_sets)) { + if (!gpu_pbvh_is_looptri_visible(lt, hide_poly)) { continue; } @@ -355,7 +351,7 @@ void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id, buffers->mloop[lt->tri[2]].v, }; - if (!gpu_pbvh_is_looptri_visible(lt, hide_vert, buffers->mloop, sculpt_face_sets)) { + if (!gpu_pbvh_is_looptri_visible(lt, hide_poly)) { continue; } @@ -395,7 +391,7 @@ void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id, buffers->mloop[lt->tri[2]].v, }; - if (!gpu_pbvh_is_looptri_visible(lt, hide_vert, buffers->mloop, sculpt_face_sets)) { + if (!gpu_pbvh_is_looptri_visible(lt, hide_poly)) { continue; } @@ -458,7 +454,6 @@ void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id, GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const Mesh *mesh, const MLoopTri *looptri, - const int *sculpt_face_sets, const int *face_indices, const int face_indices_len) { @@ -471,8 +466,8 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const Mesh *mesh, buffers = MEM_callocN(sizeof(GPU_PBVH_Buffers), "GPU_Buffers"); - const bool *hide_vert = (bool *)CustomData_get_layer_named( - &mesh->vdata, CD_PROP_BOOL, ".hide_vert"); + const bool *hide_poly = (bool *)CustomData_get_layer_named( + &mesh->pdata, CD_PROP_BOOL, ".hide_poly"); /* smooth or flat for all */ buffers->smooth = polys[looptri[face_indices[0]].poly].flag & ME_SMOOTH; @@ -482,7 +477,7 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const Mesh *mesh, /* Count the number of visible triangles */ for (i = 0, tottri = 0; i < face_indices_len; i++) { const MLoopTri *lt = &looptri[face_indices[i]]; - if (gpu_pbvh_is_looptri_visible(lt, hide_vert, loops, sculpt_face_sets)) { + if (gpu_pbvh_is_looptri_visible(lt, hide_poly)) { int r_edges[3]; BKE_mesh_looptri_get_real_edges(mesh, lt, r_edges); for (int j = 0; j < 3; j++) { @@ -515,7 +510,7 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const Mesh *mesh, const MLoopTri *lt = &looptri[face_indices[i]]; /* Skip hidden faces */ - if (!gpu_pbvh_is_looptri_visible(lt, hide_vert, loops, sculpt_face_sets)) { + if (!gpu_pbvh_is_looptri_visible(lt, hide_poly)) { continue; } diff --git a/source/blender/gpu/intern/gpu_shader_builder_stubs.cc b/source/blender/gpu/intern/gpu_shader_builder_stubs.cc index 0c8cec4e7dc..6202a97901f 100644 --- a/source/blender/gpu/intern/gpu_shader_builder_stubs.cc +++ b/source/blender/gpu/intern/gpu_shader_builder_stubs.cc @@ -136,9 +136,7 @@ eAttrDomain BKE_id_attribute_domain(const struct ID *UNUSED(id), /* -------------------------------------------------------------------- */ /** \name Stubs of BKE_paint.h * \{ */ -bool paint_is_face_hidden(const struct MLoopTri *UNUSED(lt), - const bool *UNUSED(hide_vert), - const struct MLoop *UNUSED(mloop)) +bool paint_is_face_hidden(const struct MLoopTri *UNUSED(lt), const bool *UNUSED(hide_poly)) { BLI_assert_unreachable(); return false; diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index 6881916d1d2..7e652e31506 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -809,7 +809,7 @@ bool imb_addrectImBuf(struct ImBuf *ibuf); */ void imb_freerectImBuf(struct ImBuf *ibuf); -bool imb_addrectfloatImBuf(struct ImBuf *ibuf); +bool imb_addrectfloatImBuf(struct ImBuf *ibuf, const unsigned int channels); /** * Any free `ibuf->rect` frees mipmaps to be sure, creation is in render on first request. */ diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h index 45d05e9b856..03bb11d0cf6 100644 --- a/source/blender/imbuf/IMB_imbuf_types.h +++ b/source/blender/imbuf/IMB_imbuf_types.h @@ -166,8 +166,6 @@ typedef enum eImBufFlags { * \{ */ typedef struct ImBuf { - struct ImBuf *next, *prev; /** < allow lists of #ImBufs, for caches or flip-books. */ - /* dimensions */ /** Width and Height of our image buffer. * Should be 'unsigned int' since most formats use this. diff --git a/source/blender/imbuf/intern/IMB_filetype.h b/source/blender/imbuf/intern/IMB_filetype.h index 9a0a6998fab..bd17316d173 100644 --- a/source/blender/imbuf/intern/IMB_filetype.h +++ b/source/blender/imbuf/intern/IMB_filetype.h @@ -264,6 +264,12 @@ struct ImBuf *imb_loadwebp(const unsigned char *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE]); +struct ImBuf *imb_load_filepath_thumbnail_webp(const char *filepath, + const int flags, + const size_t max_thumb_size, + char colorspace[], + size_t *r_width, + size_t *r_height); bool imb_savewebp(struct ImBuf *ibuf, const char *name, int flags); /** \} */ diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c index 8b9ad94de0c..868040dc17a 100644 --- a/source/blender/imbuf/intern/allocimbuf.c +++ b/source/blender/imbuf/intern/allocimbuf.c @@ -364,7 +364,7 @@ void *imb_alloc_pixels( return MEM_callocN(size, name); } -bool imb_addrectfloatImBuf(ImBuf *ibuf) +bool imb_addrectfloatImBuf(ImBuf *ibuf, const unsigned int channels) { if (ibuf == NULL) { return false; @@ -374,8 +374,8 @@ bool imb_addrectfloatImBuf(ImBuf *ibuf) imb_freerectfloatImBuf(ibuf); /* frees mipmap too, hrm */ } - ibuf->channels = 4; - if ((ibuf->rect_float = imb_alloc_pixels(ibuf->x, ibuf->y, 4, sizeof(float), __func__))) { + ibuf->channels = channels; + if ((ibuf->rect_float = imb_alloc_pixels(ibuf->x, ibuf->y, channels, sizeof(float), __func__))) { ibuf->mall |= IB_rectfloat; ibuf->flags |= IB_rectfloat; return true; @@ -536,7 +536,7 @@ bool IMB_initImBuf( } if (flags & IB_rectfloat) { - if (imb_addrectfloatImBuf(ibuf) == false) { + if (imb_addrectfloatImBuf(ibuf, ibuf->channels) == false) { return false; } } diff --git a/source/blender/imbuf/intern/filetype.c b/source/blender/imbuf/intern/filetype.c index 92fa980cd7f..e1d2bea4ae9 100644 --- a/source/blender/imbuf/intern/filetype.c +++ b/source/blender/imbuf/intern/filetype.c @@ -217,7 +217,7 @@ const ImFileType IMB_FILE_TYPES[] = { .is_a = imb_is_a_webp, .load = imb_loadwebp, .load_filepath = NULL, - .load_filepath_thumbnail = NULL, + .load_filepath_thumbnail = imb_load_filepath_thumbnail_webp, .save = imb_savewebp, .load_tile = NULL, .flag = 0, diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index eb6ce5df794..aaeb407abc4 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -2058,7 +2058,7 @@ struct ImBuf *imb_load_openexr(const unsigned char *mem, size_t xstride = sizeof(float[4]); size_t ystride = -xstride * width; - imb_addrectfloatImBuf(ibuf); + imb_addrectfloatImBuf(ibuf, 4); /* Inverse correct first pixel for data-window * coordinates (- dw.min.y because of y flip). */ diff --git a/source/blender/imbuf/intern/png.c b/source/blender/imbuf/intern/png.c index 4d6dfac0ba0..e27d649ccbe 100644 --- a/source/blender/imbuf/intern/png.c +++ b/source/blender/imbuf/intern/png.c @@ -646,7 +646,7 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors if (ibuf && ((flags & IB_test) == 0)) { if (bit_depth == 16) { - imb_addrectfloatImBuf(ibuf); + imb_addrectfloatImBuf(ibuf, 4); png_set_swap(png_ptr); pixels16 = imb_alloc_pixels(ibuf->x, ibuf->y, channels, sizeof(png_uint_16), "pixels"); diff --git a/source/blender/imbuf/intern/stereoimbuf.c b/source/blender/imbuf/intern/stereoimbuf.c index 2a0baaf6172..ba1840a5fcd 100644 --- a/source/blender/imbuf/intern/stereoimbuf.c +++ b/source/blender/imbuf/intern/stereoimbuf.c @@ -761,11 +761,14 @@ ImBuf *IMB_stereo3d_ImBuf(const ImageFormatData *im_format, ImBuf *ibuf_left, Im IMB_stereo3d_write_dimensions( im_format->stereo3d_format.display_mode, false, ibuf_left->x, ibuf_left->y, &width, &height); - ibuf_stereo = IMB_allocImBuf( - width, height, ibuf_left->planes, (is_float ? IB_rectfloat : IB_rect)); + ibuf_stereo = IMB_allocImBuf(width, height, ibuf_left->planes, 0); - ibuf_stereo->rect_colorspace = ibuf_left->rect_colorspace; - ibuf_stereo->float_colorspace = ibuf_left->float_colorspace; + if (is_float) { + imb_addrectfloatImBuf(ibuf_stereo, ibuf_left->channels); + } + else { + imb_addrectImBuf(ibuf_stereo); + } ibuf_stereo->flags = ibuf_left->flags; @@ -773,7 +776,7 @@ ImBuf *IMB_stereo3d_ImBuf(const ImageFormatData *im_format, ImBuf *ibuf_left, Im is_float, ibuf_left->x, ibuf_left->y, - 4, + ibuf_left->channels, (int *)ibuf_left->rect, (int *)ibuf_right->rect, (int *)ibuf_stereo->rect, @@ -1286,10 +1289,17 @@ void IMB_ImBufFromStereo3d(const Stereo3dFormat *s3d, &width, &height); - ibuf_left = IMB_allocImBuf( - width, height, ibuf_stereo3d->planes, (is_float ? IB_rectfloat : IB_rect)); - ibuf_right = IMB_allocImBuf( - width, height, ibuf_stereo3d->planes, (is_float ? IB_rectfloat : IB_rect)); + ibuf_left = IMB_allocImBuf(width, height, ibuf_stereo3d->planes, 0); + ibuf_right = IMB_allocImBuf(width, height, ibuf_stereo3d->planes, 0); + + if (is_float) { + imb_addrectfloatImBuf(ibuf_left, ibuf_stereo3d->channels); + imb_addrectfloatImBuf(ibuf_right, ibuf_stereo3d->channels); + } + else { + imb_addrectImBuf(ibuf_left); + imb_addrectImBuf(ibuf_right); + } ibuf_left->flags = ibuf_stereo3d->flags; ibuf_right->flags = ibuf_stereo3d->flags; @@ -1307,7 +1317,7 @@ void IMB_ImBufFromStereo3d(const Stereo3dFormat *s3d, is_float, ibuf_left->x, ibuf_left->y, - 4, + ibuf_left->channels, (int *)ibuf_left->rect, (int *)ibuf_right->rect, (int *)ibuf_stereo3d->rect, diff --git a/source/blender/imbuf/intern/webp.c b/source/blender/imbuf/intern/webp.c index 19fe2373ea0..94c8e3fb61d 100644 --- a/source/blender/imbuf/intern/webp.c +++ b/source/blender/imbuf/intern/webp.c @@ -4,14 +4,23 @@ * \ingroup imbuf */ +#ifdef _WIN32 +# include <io.h> +#else +# include <unistd.h> +#endif + +#include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <webp/decode.h> #include <webp/encode.h> #include "BLI_fileops.h" +#include "BLI_mmap.h" #include "BLI_utildefines.h" +#include "IMB_allocimbuf.h" #include "IMB_colormanagement.h" #include "IMB_colormanagement_intern.h" #include "IMB_filetype.h" @@ -67,6 +76,89 @@ ImBuf *imb_loadwebp(const unsigned char *mem, return ibuf; } +struct ImBuf *imb_load_filepath_thumbnail_webp(const char *filepath, + const int UNUSED(flags), + const size_t max_thumb_size, + char colorspace[], + size_t *r_width, + size_t *r_height) +{ + const int file = BLI_open(filepath, O_BINARY | O_RDONLY, 0); + if (file == -1) { + return NULL; + } + + const size_t data_size = BLI_file_descriptor_size(file); + + imb_mmap_lock(); + BLI_mmap_file *mmap_file = BLI_mmap_open(file); + imb_mmap_unlock(); + close(file); + if (mmap_file == NULL) { + return NULL; + } + + const unsigned char *data = BLI_mmap_get_pointer(mmap_file); + + WebPDecoderConfig config; + if (!data || !WebPInitDecoderConfig(&config) || + WebPGetFeatures(data, data_size, &config.input) != VP8_STATUS_OK) { + fprintf(stderr, "WebP: Invalid file\n"); + imb_mmap_lock(); + BLI_mmap_free(mmap_file); + imb_mmap_unlock(); + return NULL; + } + + /* Return full size of the image. */ + *r_width = (size_t)config.input.width; + *r_height = (size_t)config.input.height; + + const float scale = (float)max_thumb_size / MAX2(config.input.width, config.input.height); + const int dest_w = (int)(config.input.width * scale); + const int dest_h = (int)(config.input.height * scale); + + colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE); + struct ImBuf *ibuf = IMB_allocImBuf(dest_w, dest_h, 32, IB_rect); + if (ibuf == NULL) { + fprintf(stderr, "WebP: Failed to allocate image memory\n"); + imb_mmap_lock(); + BLI_mmap_free(mmap_file); + imb_mmap_unlock(); + return NULL; + } + + config.options.no_fancy_upsampling = 1; + config.options.use_scaling = 1; + config.options.scaled_width = dest_w; + config.options.scaled_height = dest_h; + config.options.bypass_filtering = 1; + config.options.use_threads = 0; + config.options.flip = 1; + config.output.is_external_memory = 1; + config.output.colorspace = MODE_RGBA; + config.output.u.RGBA.rgba = (uint8_t *)ibuf->rect; + config.output.u.RGBA.stride = 4 * ibuf->x; + config.output.u.RGBA.size = (size_t)(config.output.u.RGBA.stride * ibuf->y); + + if (WebPDecode(data, data_size, &config) != VP8_STATUS_OK) { + fprintf(stderr, "WebP: Failed to decode image\n"); + imb_mmap_lock(); + BLI_mmap_free(mmap_file); + imb_mmap_unlock(); + return NULL; + } + + /* Free the output buffer. */ + WebPFreeDecBuffer(&config.output); + + imb_mmap_lock(); + BLI_mmap_free(mmap_file); + imb_mmap_unlock(); + + return ibuf; +} + bool imb_savewebp(struct ImBuf *ibuf, const char *name, int UNUSED(flags)) { const int bytesperpixel = (ibuf->planes + 7) >> 3; diff --git a/source/blender/io/usd/usd.h b/source/blender/io/usd/usd.h index a07315d8b4e..3494d8ffdc3 100644 --- a/source/blender/io/usd/usd.h +++ b/source/blender/io/usd/usd.h @@ -52,7 +52,7 @@ struct USDImportParams { bool import_materials; bool import_meshes; bool import_volumes; - char *prim_path_mask; + char prim_path_mask[1024]; bool import_subdiv; bool import_instance_proxies; bool create_collection; diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc index 4d934960010..27526734624 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc @@ -558,24 +558,26 @@ void MTLWriter::write_bsdf_properties(const MTLMaterial &mtl) /* For various material properties, we only capture information * coming from the texture, or the default value of the socket. * When the texture is present, do not emit the default value. */ - if (!mtl.tex_map_of_type(MTLTexMapType::Ns).is_valid()) { - fmt_handler_.write_mtl_float("Ns", mtl.Ns); + if (!mtl.tex_map_of_type(MTLTexMapType::SpecularExponent).is_valid()) { + fmt_handler_.write_mtl_float("Ns", mtl.spec_exponent); } - fmt_handler_.write_mtl_float3("Ka", mtl.Ka.x, mtl.Ka.y, mtl.Ka.z); - if (!mtl.tex_map_of_type(MTLTexMapType::Kd).is_valid()) { - fmt_handler_.write_mtl_float3("Kd", mtl.Kd.x, mtl.Kd.y, mtl.Kd.z); + fmt_handler_.write_mtl_float3( + "Ka", mtl.ambient_color.x, mtl.ambient_color.y, mtl.ambient_color.z); + if (!mtl.tex_map_of_type(MTLTexMapType::Color).is_valid()) { + fmt_handler_.write_mtl_float3("Kd", mtl.color.x, mtl.color.y, mtl.color.z); } - if (!mtl.tex_map_of_type(MTLTexMapType::Ks).is_valid()) { - fmt_handler_.write_mtl_float3("Ks", mtl.Ks.x, mtl.Ks.y, mtl.Ks.z); + if (!mtl.tex_map_of_type(MTLTexMapType::Specular).is_valid()) { + fmt_handler_.write_mtl_float3("Ks", mtl.spec_color.x, mtl.spec_color.y, mtl.spec_color.z); } - if (!mtl.tex_map_of_type(MTLTexMapType::Ke).is_valid()) { - fmt_handler_.write_mtl_float3("Ke", mtl.Ke.x, mtl.Ke.y, mtl.Ke.z); + if (!mtl.tex_map_of_type(MTLTexMapType::Emission).is_valid()) { + fmt_handler_.write_mtl_float3( + "Ke", mtl.emission_color.x, mtl.emission_color.y, mtl.emission_color.z); } - fmt_handler_.write_mtl_float("Ni", mtl.Ni); - if (!mtl.tex_map_of_type(MTLTexMapType::d).is_valid()) { - fmt_handler_.write_mtl_float("d", mtl.d); + fmt_handler_.write_mtl_float("Ni", mtl.ior); + if (!mtl.tex_map_of_type(MTLTexMapType::Alpha).is_valid()) { + fmt_handler_.write_mtl_float("d", mtl.alpha); } - fmt_handler_.write_mtl_illum(mtl.illum); + fmt_handler_.write_mtl_illum(mtl.illum_mode); } void MTLWriter::write_texture_map(const MTLMaterial &mtl_material, @@ -594,8 +596,8 @@ void MTLWriter::write_texture_map(const MTLMaterial &mtl_material, if (texture_map.scale != float3{1.0f, 1.0f, 1.0f}) { options.append(" -s ").append(float3_to_string(texture_map.scale)); } - if (texture_key == MTLTexMapType::bump && mtl_material.map_Bump_strength > 0.0001f) { - options.append(" -bm ").append(std::to_string(mtl_material.map_Bump_strength)); + if (texture_key == MTLTexMapType::Normal && mtl_material.normal_strength > 0.0001f) { + options.append(" -bm ").append(std::to_string(mtl_material.normal_strength)); } std::string path = path_reference( diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc index 6a02695c304..77cad18a040 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc @@ -212,11 +212,11 @@ static void store_bsdf_properties(const bNode *bsdf_node, copy_property_from_node(SOCK_FLOAT, bsdf_node, "IOR", {&refraction_index, 1}); } - float dissolved = material->a; + float alpha = material->a; if (bsdf_node) { - copy_property_from_node(SOCK_FLOAT, bsdf_node, "Alpha", {&dissolved, 1}); + copy_property_from_node(SOCK_FLOAT, bsdf_node, "Alpha", {&alpha, 1}); } - const bool transparent = dissolved != 1.0f; + const bool transparent = alpha != 1.0f; float3 diffuse_col = {material->r, material->g, material->b}; if (bsdf_node) { @@ -253,19 +253,19 @@ static void store_bsdf_properties(const bNode *bsdf_node, /* Transparency: Glass on, Reflection: Ray trace off */ illum = 9; } - r_mtl_mat.Ns = spec_exponent; + r_mtl_mat.spec_exponent = spec_exponent; if (metallic != 0.0f) { - r_mtl_mat.Ka = {metallic, metallic, metallic}; + r_mtl_mat.ambient_color = {metallic, metallic, metallic}; } else { - r_mtl_mat.Ka = {1.0f, 1.0f, 1.0f}; + r_mtl_mat.ambient_color = {1.0f, 1.0f, 1.0f}; } - r_mtl_mat.Kd = diffuse_col; - r_mtl_mat.Ks = {specular, specular, specular}; - r_mtl_mat.Ke = emission_col; - r_mtl_mat.Ni = refraction_index; - r_mtl_mat.d = dissolved; - r_mtl_mat.illum = illum; + r_mtl_mat.color = diffuse_col; + r_mtl_mat.spec_color = {specular, specular, specular}; + r_mtl_mat.emission_color = emission_col; + r_mtl_mat.ior = refraction_index; + r_mtl_mat.alpha = alpha; + r_mtl_mat.illum_mode = illum; } /** @@ -291,7 +291,7 @@ static void store_image_textures(const bNode *bsdf_node, Vector<const bNodeSocket *> linked_sockets; const bNode *normal_map_node{nullptr}; - if (key == (int)MTLTexMapType::bump) { + if (key == (int)MTLTexMapType::Normal) { /* Find sockets linked to destination "Normal" socket in P-BSDF node. */ linked_sockets_to_dest_id(bsdf_node, *node_tree, "Normal", linked_sockets); /* Among the linked sockets, find Normal Map shader node. */ @@ -302,7 +302,7 @@ static void store_image_textures(const bNode *bsdf_node, } else { /* Skip emission map if emission strength is zero. */ - if (key == (int)MTLTexMapType::Ke) { + if (key == (int)MTLTexMapType::Emission) { float emission_strength = 0.0f; copy_property_from_node( SOCK_FLOAT, bsdf_node, "Emission Strength", {&emission_strength, 1}); @@ -331,7 +331,7 @@ static void store_image_textures(const bNode *bsdf_node, if (normal_map_node) { copy_property_from_node( - SOCK_FLOAT, normal_map_node, "Strength", {&r_mtl_mat.map_Bump_strength, 1}); + SOCK_FLOAT, normal_map_node, "Strength", {&r_mtl_mat.normal_strength, 1}); } /* Texture transform options. Only translation (origin offset, "-o") and scale * ("-o") are supported. */ diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mtl.hh b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.hh index d8eafff107b..0b94e4e43a3 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_mtl.hh +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.hh @@ -13,7 +13,16 @@ struct Material; namespace blender::io::obj { -enum class MTLTexMapType { Kd = 0, Ks, Ns, d, refl, Ke, bump, Count }; +enum class MTLTexMapType { + Color = 0, + Specular, + SpecularExponent, + Alpha, + Reflection, + Emission, + Normal, + Count +}; extern const char *tex_map_type_to_socket_id[]; struct MTLTexMap { @@ -47,17 +56,17 @@ struct MTLMaterial { std::string name; /* Always check for negative values while importing or exporting. Use defaults if * any value is negative. */ - float Ns{-1.0f}; - float3 Ka{-1.0f}; - float3 Kd{-1.0f}; - float3 Ks{-1.0f}; - float3 Ke{-1.0f}; - float Ni{-1.0f}; - float d{-1.0f}; - int illum{-1}; + float spec_exponent{-1.0f}; /* Ns */ + float3 ambient_color{-1.0f}; /* Ka */ + float3 color{-1.0f}; /* Kd */ + float3 spec_color{-1.0f}; /* Ks */ + float3 emission_color{-1.0f}; /* Ke */ + float ior{-1.0f}; /* Ni */ + float alpha{-1.0f}; /* d */ + int illum_mode{-1}; MTLTexMap texture_maps[(int)MTLTexMapType::Count]; - /** Only used for Normal Map node: "map_Bump". */ - float map_Bump_strength{-1.0f}; + /* Only used for Normal Map node: "map_Bump". */ + float normal_strength{-1.0f}; }; MTLMaterial mtlmaterial_for_material(const Material *material); diff --git a/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc b/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc index 2ad8a09bd90..cc98dbdbf92 100644 --- a/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc +++ b/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc @@ -596,26 +596,26 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries, static MTLTexMapType mtl_line_start_to_texture_type(const char *&p, const char *end) { if (parse_keyword(p, end, "map_Kd")) { - return MTLTexMapType::Kd; + return MTLTexMapType::Color; } if (parse_keyword(p, end, "map_Ks")) { - return MTLTexMapType::Ks; + return MTLTexMapType::Specular; } if (parse_keyword(p, end, "map_Ns")) { - return MTLTexMapType::Ns; + return MTLTexMapType::SpecularExponent; } if (parse_keyword(p, end, "map_d")) { - return MTLTexMapType::d; + return MTLTexMapType::Alpha; } if (parse_keyword(p, end, "refl") || parse_keyword(p, end, "map_refl")) { - return MTLTexMapType::refl; + return MTLTexMapType::Reflection; } if (parse_keyword(p, end, "map_Ke")) { - return MTLTexMapType::Ke; + return MTLTexMapType::Emission; } if (parse_keyword(p, end, "bump") || parse_keyword(p, end, "map_Bump") || parse_keyword(p, end, "map_bump")) { - return MTLTexMapType::bump; + return MTLTexMapType::Normal; } return MTLTexMapType::Count; } @@ -647,7 +647,7 @@ static bool parse_texture_option(const char *&p, return true; } if (parse_keyword(p, end, "-bm")) { - p = parse_float(p, end, 1.0f, material->map_Bump_strength, true, true); + p = parse_float(p, end, 1.0f, material->normal_strength, true, true); return true; } if (parse_keyword(p, end, "-type")) { @@ -780,31 +780,31 @@ void MTLParser::parse_and_store(Map<string, std::unique_ptr<MTLMaterial>> &r_mat } else if (material != nullptr) { if (parse_keyword(p, end, "Ns")) { - parse_float(p, end, 324.0f, material->Ns); + parse_float(p, end, 324.0f, material->spec_exponent); } else if (parse_keyword(p, end, "Ka")) { - parse_floats(p, end, 0.0f, material->Ka, 3); + parse_floats(p, end, 0.0f, material->ambient_color, 3); } else if (parse_keyword(p, end, "Kd")) { - parse_floats(p, end, 0.8f, material->Kd, 3); + parse_floats(p, end, 0.8f, material->color, 3); } else if (parse_keyword(p, end, "Ks")) { - parse_floats(p, end, 0.5f, material->Ks, 3); + parse_floats(p, end, 0.5f, material->spec_color, 3); } else if (parse_keyword(p, end, "Ke")) { - parse_floats(p, end, 0.0f, material->Ke, 3); + parse_floats(p, end, 0.0f, material->emission_color, 3); } else if (parse_keyword(p, end, "Ni")) { - parse_float(p, end, 1.45f, material->Ni); + parse_float(p, end, 1.45f, material->ior); } else if (parse_keyword(p, end, "d")) { - parse_float(p, end, 1.0f, material->d); + parse_float(p, end, 1.0f, material->alpha); } else if (parse_keyword(p, end, "illum")) { /* Some files incorrectly use a float (T60135). */ float val; parse_float(p, end, 1.0f, val); - material->illum = val; + material->illum_mode = val; } else { parse_texture_map(p, end, material, mtl_dir_path_); diff --git a/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc b/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc index 0922a71979e..76568b2ddb4 100644 --- a/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc +++ b/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc @@ -178,7 +178,7 @@ static void link_sockets(bNodeTree *ntree, static void set_bsdf_socket_values(bNode *bsdf, Material *mat, const MTLMaterial &mtl_mat) { - const int illum = mtl_mat.illum; + const int illum = mtl_mat.illum_mode; bool do_highlight = false; bool do_tranparency = false; bool do_reflection = false; @@ -244,21 +244,23 @@ static void set_bsdf_socket_values(bNode *bsdf, Material *mat, const MTLMaterial /* Approximations for trying to map obj/mtl material model into * Principled BSDF: */ /* Specular: average of Ks components. */ - float specular = (mtl_mat.Ks[0] + mtl_mat.Ks[1] + mtl_mat.Ks[2]) / 3; + float specular = (mtl_mat.spec_color[0] + mtl_mat.spec_color[1] + mtl_mat.spec_color[2]) / 3; if (specular < 0.0f) { specular = do_highlight ? 1.0f : 0.0f; } /* Roughness: map 0..1000 range to 1..0 and apply non-linearity. */ float roughness; - if (mtl_mat.Ns < 0.0f) { + if (mtl_mat.spec_exponent < 0.0f) { roughness = do_highlight ? 0.0f : 1.0f; } else { - float clamped_ns = std::max(0.0f, std::min(1000.0f, mtl_mat.Ns)); + float clamped_ns = std::max(0.0f, std::min(1000.0f, mtl_mat.spec_exponent)); roughness = 1.0f - sqrt(clamped_ns / 1000.0f); } /* Metallic: average of Ka components. */ - float metallic = (mtl_mat.Ka[0] + mtl_mat.Ka[1] + mtl_mat.Ka[2]) / 3; + float metallic = (mtl_mat.ambient_color[0] + mtl_mat.ambient_color[1] + + mtl_mat.ambient_color[2]) / + 3; if (do_reflection) { if (metallic < 0.0f) { metallic = 1.0f; @@ -268,7 +270,7 @@ static void set_bsdf_socket_values(bNode *bsdf, Material *mat, const MTLMaterial metallic = 0.0f; } - float ior = mtl_mat.Ni; + float ior = mtl_mat.ior; if (ior < 0) { if (do_tranparency) { ior = 1.0f; @@ -277,12 +279,12 @@ static void set_bsdf_socket_values(bNode *bsdf, Material *mat, const MTLMaterial ior = 1.5f; } } - float alpha = mtl_mat.d; + float alpha = mtl_mat.alpha; if (do_tranparency && alpha < 0) { alpha = 1.0f; } - float3 base_color = {mtl_mat.Kd[0], mtl_mat.Kd[1], mtl_mat.Kd[2]}; + float3 base_color = mtl_mat.color; if (base_color.x >= 0 && base_color.y >= 0 && base_color.z >= 0) { set_property_of_socket(SOCK_RGBA, "Base Color", {base_color, 3}, bsdf); /* Viewport shading uses legacy r,g,b base color. */ @@ -291,11 +293,11 @@ static void set_bsdf_socket_values(bNode *bsdf, Material *mat, const MTLMaterial mat->b = base_color.z; } - float3 emission_color = {mtl_mat.Ke[0], mtl_mat.Ke[1], mtl_mat.Ke[2]}; + float3 emission_color = mtl_mat.emission_color; if (emission_color.x >= 0 && emission_color.y >= 0 && emission_color.z >= 0) { set_property_of_socket(SOCK_RGBA, "Emission", {emission_color, 3}, bsdf); } - if (mtl_mat.tex_map_of_type(MTLTexMapType::Ke).is_valid()) { + if (mtl_mat.tex_map_of_type(MTLTexMapType::Emission).is_valid()) { set_property_of_socket(SOCK_FLOAT, "Emission Strength", {1.0f}, bsdf); } set_property_of_socket(SOCK_FLOAT, "Specular", {specular}, bsdf); @@ -341,9 +343,9 @@ static void add_image_textures(Main *bmain, /* Add normal map node if needed. */ bNode *normal_map = nullptr; - if (key == (int)MTLTexMapType::bump) { + if (key == (int)MTLTexMapType::Normal) { normal_map = add_node(ntree, SH_NODE_NORMAL_MAP, node_locx_normalmap, node_locy); - const float bump = std::max(0.0f, mtl_mat.map_Bump_strength); + const float bump = std::max(0.0f, mtl_mat.normal_strength); set_property_of_socket(SOCK_FLOAT, "Strength", {bump}, normal_map); } @@ -362,7 +364,7 @@ static void add_image_textures(Main *bmain, link_sockets(ntree, image_node, "Color", normal_map, "Color"); link_sockets(ntree, normal_map, "Normal", bsdf, "Normal"); } - else if (key == (int)MTLTexMapType::d) { + else if (key == (int)MTLTexMapType::Alpha) { link_sockets(ntree, image_node, "Alpha", bsdf, tex_map_type_to_socket_id[key]); mat->blend_method = MA_BM_BLEND; } diff --git a/source/blender/io/wavefront_obj/tests/obj_mtl_parser_tests.cc b/source/blender/io/wavefront_obj/tests/obj_mtl_parser_tests.cc index 5691aa5bea1..ff9485e99b5 100644 --- a/source/blender/io/wavefront_obj/tests/obj_mtl_parser_tests.cc +++ b/source/blender/io/wavefront_obj/tests/obj_mtl_parser_tests.cc @@ -50,15 +50,15 @@ class obj_mtl_parser_test : public testing::Test { } const MTLMaterial &got = *materials.lookup(exp.name); const float tol = 0.0001f; - EXPECT_V3_NEAR(exp.Ka, got.Ka, tol); - EXPECT_V3_NEAR(exp.Kd, got.Kd, tol); - EXPECT_V3_NEAR(exp.Ks, got.Ks, tol); - EXPECT_V3_NEAR(exp.Ke, got.Ke, tol); - EXPECT_NEAR(exp.Ns, got.Ns, tol); - EXPECT_NEAR(exp.Ni, got.Ni, tol); - EXPECT_NEAR(exp.d, got.d, tol); - EXPECT_NEAR(exp.map_Bump_strength, got.map_Bump_strength, tol); - EXPECT_EQ(exp.illum, got.illum); + EXPECT_V3_NEAR(exp.ambient_color, got.ambient_color, tol); + EXPECT_V3_NEAR(exp.color, got.color, tol); + EXPECT_V3_NEAR(exp.spec_color, got.spec_color, tol); + EXPECT_V3_NEAR(exp.emission_color, got.emission_color, tol); + EXPECT_NEAR(exp.spec_exponent, got.spec_exponent, tol); + EXPECT_NEAR(exp.ior, got.ior, tol); + EXPECT_NEAR(exp.alpha, got.alpha, tol); + EXPECT_NEAR(exp.normal_strength, got.normal_strength, tol); + EXPECT_EQ(exp.illum_mode, got.illum_mode); for (int key = 0; key < (int)MTLTexMapType::Count; key++) { const MTLTexMap &exp_tex = exp.texture_maps[key]; const MTLTexMap &got_tex = got.texture_maps[key]; @@ -102,20 +102,20 @@ TEST_F(obj_mtl_parser_test, string_newlines_whitespace) "map_Ks sometex_s_spaces_after_name.png \t \r\n"; MTLMaterial mat[6]; mat[0].name = "simple"; - mat[0].Ka = {0.1f, 0.2f, 0.3f}; - mat[0].illum = 4; + mat[0].ambient_color = {0.1f, 0.2f, 0.3f}; + mat[0].illum_mode = 4; mat[1].name = "tab_indentation"; - mat[1].Kd = {0.2f, 0.3f, 0.4f}; + mat[1].color = {0.2f, 0.3f, 0.4f}; mat[2].name = "space_after_name"; - mat[2].Ks = {0.4f, 0.5f, 0.6f}; + mat[2].spec_color = {0.4f, 0.5f, 0.6f}; mat[3].name = "space_before_name"; mat[4].name = "indented_values"; - mat[4].Ka = {0.5f, 0.6f, 0.7f}; - mat[4].Kd = {0.6f, 0.7f, 0.8f}; + mat[4].ambient_color = {0.5f, 0.6f, 0.7f}; + mat[4].color = {0.6f, 0.7f, 0.8f}; mat[5].name = "crlf_ending"; - mat[5].Ns = 5.0f; - mat[5].tex_map_of_type(MTLTexMapType::Kd).image_path = "sometex_d.png"; - mat[5].tex_map_of_type(MTLTexMapType::Ks).image_path = "sometex_s_spaces_after_name.png"; + mat[5].spec_exponent = 5.0f; + mat[5].tex_map_of_type(MTLTexMapType::Color).image_path = "sometex_d.png"; + mat[5].tex_map_of_type(MTLTexMapType::Specular).image_path = "sometex_s_spaces_after_name.png"; check_string(text, mat, ARRAY_SIZE(mat)); } @@ -123,8 +123,8 @@ TEST_F(obj_mtl_parser_test, cube) { MTLMaterial mat; mat.name = "red"; - mat.Ka = {0.2f, 0.2f, 0.2f}; - mat.Kd = {1, 0, 0}; + mat.ambient_color = {0.2f, 0.2f, 0.2f}; + mat.color = {1, 0, 0}; check("cube.mtl", &mat, 1); } @@ -132,28 +132,28 @@ TEST_F(obj_mtl_parser_test, all_objects) { MTLMaterial mat[7]; for (auto &m : mat) { - m.Ka = {1, 1, 1}; - m.Ks = {0.5f, 0.5f, 0.5f}; - m.Ke = {0, 0, 0}; - m.Ns = 250; - m.Ni = 1; - m.d = 1; - m.illum = 2; + m.ambient_color = {1, 1, 1}; + m.spec_color = {0.5f, 0.5f, 0.5f}; + m.emission_color = {0, 0, 0}; + m.spec_exponent = 250; + m.ior = 1; + m.alpha = 1; + m.illum_mode = 2; } mat[0].name = "Blue"; - mat[0].Kd = {0, 0, 1}; + mat[0].color = {0, 0, 1}; mat[1].name = "BlueDark"; - mat[1].Kd = {0, 0, 0.5f}; + mat[1].color = {0, 0, 0.5f}; mat[2].name = "Green"; - mat[2].Kd = {0, 1, 0}; + mat[2].color = {0, 1, 0}; mat[3].name = "GreenDark"; - mat[3].Kd = {0, 0.5f, 0}; + mat[3].color = {0, 0.5f, 0}; mat[4].name = "Material"; - mat[4].Kd = {0.8f, 0.8f, 0.8f}; + mat[4].color = {0.8f, 0.8f, 0.8f}; mat[5].name = "Red"; - mat[5].Kd = {1, 0, 0}; + mat[5].color = {1, 0, 0}; mat[6].name = "RedDark"; - mat[6].Kd = {0.5f, 0, 0}; + mat[6].color = {0.5f, 0, 0}; check("all_objects.mtl", mat, ARRAY_SIZE(mat)); } @@ -161,92 +161,92 @@ TEST_F(obj_mtl_parser_test, materials) { MTLMaterial mat[6]; mat[0].name = "no_textures_red"; - mat[0].Ka = {0.3f, 0.3f, 0.3f}; - mat[0].Kd = {0.8f, 0.3f, 0.1f}; - mat[0].Ns = 5.624998f; + mat[0].ambient_color = {0.3f, 0.3f, 0.3f}; + mat[0].color = {0.8f, 0.3f, 0.1f}; + mat[0].spec_exponent = 5.624998f; mat[1].name = "four_maps"; - mat[1].Ka = {1, 1, 1}; - mat[1].Kd = {0.8f, 0.8f, 0.8f}; - mat[1].Ks = {0.5f, 0.5f, 0.5f}; - mat[1].Ke = {0, 0, 0}; - mat[1].Ns = 1000; - mat[1].Ni = 1.45f; - mat[1].d = 1; - mat[1].illum = 2; - mat[1].map_Bump_strength = 1; + mat[1].ambient_color = {1, 1, 1}; + mat[1].color = {0.8f, 0.8f, 0.8f}; + mat[1].spec_color = {0.5f, 0.5f, 0.5f}; + mat[1].emission_color = {0, 0, 0}; + mat[1].spec_exponent = 1000; + mat[1].ior = 1.45f; + mat[1].alpha = 1; + mat[1].illum_mode = 2; + mat[1].normal_strength = 1; { - MTLTexMap &kd = mat[1].tex_map_of_type(MTLTexMapType::Kd); + MTLTexMap &kd = mat[1].tex_map_of_type(MTLTexMapType::Color); kd.image_path = "texture.png"; - MTLTexMap &ns = mat[1].tex_map_of_type(MTLTexMapType::Ns); + MTLTexMap &ns = mat[1].tex_map_of_type(MTLTexMapType::SpecularExponent); ns.image_path = "sometexture_Roughness.png"; - MTLTexMap &refl = mat[1].tex_map_of_type(MTLTexMapType::refl); + MTLTexMap &refl = mat[1].tex_map_of_type(MTLTexMapType::Reflection); refl.image_path = "sometexture_Metallic.png"; - MTLTexMap &bump = mat[1].tex_map_of_type(MTLTexMapType::bump); + MTLTexMap &bump = mat[1].tex_map_of_type(MTLTexMapType::Normal); bump.image_path = "sometexture_Normal.png"; } mat[2].name = "Clay"; - mat[2].Ka = {1, 1, 1}; - mat[2].Kd = {0.8f, 0.682657f, 0.536371f}; - mat[2].Ks = {0.5f, 0.5f, 0.5f}; - mat[2].Ke = {0, 0, 0}; - mat[2].Ns = 440.924042f; - mat[2].Ni = 1.45f; - mat[2].d = 1; - mat[2].illum = 2; + mat[2].ambient_color = {1, 1, 1}; + mat[2].color = {0.8f, 0.682657f, 0.536371f}; + mat[2].spec_color = {0.5f, 0.5f, 0.5f}; + mat[2].emission_color = {0, 0, 0}; + mat[2].spec_exponent = 440.924042f; + mat[2].ior = 1.45f; + mat[2].alpha = 1; + mat[2].illum_mode = 2; mat[3].name = "Hat"; - mat[3].Ka = {1, 1, 1}; - mat[3].Kd = {0.8f, 0.8f, 0.8f}; - mat[3].Ks = {0.5f, 0.5f, 0.5f}; - mat[3].Ns = 800; - mat[3].map_Bump_strength = 0.5f; + mat[3].ambient_color = {1, 1, 1}; + mat[3].color = {0.8f, 0.8f, 0.8f}; + mat[3].spec_color = {0.5f, 0.5f, 0.5f}; + mat[3].spec_exponent = 800; + mat[3].normal_strength = 0.5f; { - MTLTexMap &kd = mat[3].tex_map_of_type(MTLTexMapType::Kd); + MTLTexMap &kd = mat[3].tex_map_of_type(MTLTexMapType::Color); kd.image_path = "someHatTexture_BaseColor.jpg"; - MTLTexMap &ns = mat[3].tex_map_of_type(MTLTexMapType::Ns); + MTLTexMap &ns = mat[3].tex_map_of_type(MTLTexMapType::SpecularExponent); ns.image_path = "someHatTexture_Roughness.jpg"; - MTLTexMap &refl = mat[3].tex_map_of_type(MTLTexMapType::refl); + MTLTexMap &refl = mat[3].tex_map_of_type(MTLTexMapType::Reflection); refl.image_path = "someHatTexture_Metalness.jpg"; - MTLTexMap &bump = mat[3].tex_map_of_type(MTLTexMapType::bump); + MTLTexMap &bump = mat[3].tex_map_of_type(MTLTexMapType::Normal); bump.image_path = "someHatTexture_Normal.jpg"; } mat[4].name = "Parser_Test"; - mat[4].Ka = {0.1f, 0.2f, 0.3f}; - mat[4].Kd = {0.4f, 0.5f, 0.6f}; - mat[4].Ks = {0.7f, 0.8f, 0.9f}; - mat[4].illum = 6; - mat[4].Ns = 15.5; - mat[4].Ni = 1.5; - mat[4].d = 0.5; - mat[4].map_Bump_strength = 0.1f; + mat[4].ambient_color = {0.1f, 0.2f, 0.3f}; + mat[4].color = {0.4f, 0.5f, 0.6f}; + mat[4].spec_color = {0.7f, 0.8f, 0.9f}; + mat[4].illum_mode = 6; + mat[4].spec_exponent = 15.5; + mat[4].ior = 1.5; + mat[4].alpha = 0.5; + mat[4].normal_strength = 0.1f; { - MTLTexMap &kd = mat[4].tex_map_of_type(MTLTexMapType::Kd); + MTLTexMap &kd = mat[4].tex_map_of_type(MTLTexMapType::Color); kd.image_path = "sometex_d.png"; - MTLTexMap &ns = mat[4].tex_map_of_type(MTLTexMapType::Ns); + MTLTexMap &ns = mat[4].tex_map_of_type(MTLTexMapType::SpecularExponent); ns.image_path = "sometex_ns.psd"; - MTLTexMap &refl = mat[4].tex_map_of_type(MTLTexMapType::refl); + MTLTexMap &refl = mat[4].tex_map_of_type(MTLTexMapType::Reflection); refl.image_path = "clouds.tiff"; refl.scale = {1.5f, 2.5f, 3.5f}; refl.translation = {4.5f, 5.5f, 6.5f}; refl.projection_type = SHD_PROJ_SPHERE; - MTLTexMap &bump = mat[4].tex_map_of_type(MTLTexMapType::bump); + MTLTexMap &bump = mat[4].tex_map_of_type(MTLTexMapType::Normal); bump.image_path = "somebump.tga"; bump.scale = {3, 4, 5}; } mat[5].name = "Parser_ScaleOffset_Test"; { - MTLTexMap &kd = mat[5].tex_map_of_type(MTLTexMapType::Kd); + MTLTexMap &kd = mat[5].tex_map_of_type(MTLTexMapType::Color); kd.translation = {2.5f, 0.0f, 0.0f}; kd.image_path = "OffsetOneValue.png"; - MTLTexMap &ks = mat[5].tex_map_of_type(MTLTexMapType::Ks); + MTLTexMap &ks = mat[5].tex_map_of_type(MTLTexMapType::Specular); ks.scale = {1.5f, 2.5f, 1.0f}; ks.translation = {3.5f, 4.5f, 0.0f}; ks.image_path = "ScaleOffsetBothTwovalues.png"; - MTLTexMap &ns = mat[5].tex_map_of_type(MTLTexMapType::Ns); + MTLTexMap &ns = mat[5].tex_map_of_type(MTLTexMapType::SpecularExponent); ns.scale = {0.5f, 1.0f, 1.0f}; ns.image_path = "1.Value.png"; } diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 6cbc24db2d8..cfc3a832166 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -500,7 +500,7 @@ void rna_Object_data_update(Main *bmain, Scene *scene, PointerRNA *ptr) Object *object = (Object *)ptr->data; if (object->mode == OB_MODE_SCULPT) { - BKE_sculpt_ensure_orig_mesh_data(scene, object); + BKE_sculpt_ensure_orig_mesh_data(object); } rna_Object_internal_update_data_dependency(bmain, scene, ptr); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 61d4edccb06..0031e023d39 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -6377,7 +6377,7 @@ static void rna_def_userdef_experimental(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "use_viewport_debug", 1); RNA_def_property_ui_text(prop, "Viewport Debug", - "Enable viewport debugging options for developpers in the overlays " + "Enable viewport debugging options for developers in the overlays " "pop-over"); RNA_def_property_update(prop, 0, "rna_userdef_ui_update"); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc index 3d45cb0d817..2295ae49174 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc @@ -94,24 +94,24 @@ static void expand_mesh(Mesh &mesh, const int loop_expand) { if (vert_expand != 0) { - CustomData_duplicate_referenced_layers(&mesh.vdata, mesh.totvert); + const int old_verts_num = mesh.totvert; mesh.totvert += vert_expand; - CustomData_realloc(&mesh.vdata, mesh.totvert); + CustomData_realloc(&mesh.vdata, old_verts_num, mesh.totvert); } if (edge_expand != 0) { - CustomData_duplicate_referenced_layers(&mesh.edata, mesh.totedge); + const int old_edges_num = mesh.totedge; mesh.totedge += edge_expand; - CustomData_realloc(&mesh.edata, mesh.totedge); + CustomData_realloc(&mesh.edata, old_edges_num, mesh.totedge); } if (poly_expand != 0) { - CustomData_duplicate_referenced_layers(&mesh.pdata, mesh.totpoly); + const int old_polys_num = mesh.totpoly; mesh.totpoly += poly_expand; - CustomData_realloc(&mesh.pdata, mesh.totpoly); + CustomData_realloc(&mesh.pdata, old_polys_num, mesh.totpoly); } if (loop_expand != 0) { - CustomData_duplicate_referenced_layers(&mesh.ldata, mesh.totloop); + const int old_loops_num = mesh.totloop; mesh.totloop += loop_expand; - CustomData_realloc(&mesh.ldata, mesh.totloop); + CustomData_realloc(&mesh.ldata, old_loops_num, mesh.totloop); } } @@ -147,6 +147,7 @@ static MEdge new_edge(const int v1, const int v2) MEdge edge; edge.v1 = v1; edge.v2 = v2; + edge.crease = 0; edge.flag = (ME_EDGEDRAW | ME_EDGERENDER); return edge; } @@ -156,6 +157,7 @@ static MEdge new_loose_edge(const int v1, const int v2) MEdge edge; edge.v1 = v1; edge.v2 = v2; + edge.crease = 0; edge.flag = ME_LOOSEEDGE; return edge; } @@ -286,6 +288,7 @@ static void extrude_mesh_vertices(Mesh &mesh, for (const int i : range) { const float3 offset = offsets[selection[i]]; add_v3_v3(new_verts[i].co, offset); + new_verts[i].flag = 0; } }); }); @@ -608,6 +611,7 @@ static void extrude_mesh_edges(Mesh &mesh, threading::parallel_for(new_verts.index_range(), 1024, [&](const IndexRange range) { for (const int i : range) { add_v3_v3(new_verts[i].co, offset); + new_verts[i].flag = 0; } }); } @@ -615,6 +619,7 @@ static void extrude_mesh_edges(Mesh &mesh, threading::parallel_for(new_verts.index_range(), 1024, [&](const IndexRange range) { for (const int i : range) { add_v3_v3(new_verts[i].co, vert_offsets[new_vert_indices[i]]); + new_verts[i].flag = 0; } }); } @@ -996,6 +1001,10 @@ static void extrude_mesh_face_regions(Mesh &mesh, }); } + for (MVert &vert : verts.slice(new_vert_range)) { + vert.flag = 0; + } + MutableSpan<int> vert_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_POINT); vert_orig_indices.slice(new_vert_range).fill(ORIGINDEX_NONE); @@ -1253,6 +1262,7 @@ static void extrude_individual_mesh_faces(Mesh &mesh, const IndexRange poly_corner_range = selected_corner_range(index_offsets, i_selection); for (MVert &vert : new_verts.slice(poly_corner_range)) { add_v3_v3(vert.co, poly_offset[poly_selection[i_selection]]); + vert.flag = 0; } } }); diff --git a/source/blender/render/intern/engine.cc b/source/blender/render/intern/engine.cc index a440b34af78..0024ebe38f7 100644 --- a/source/blender/render/intern/engine.cc +++ b/source/blender/render/intern/engine.cc @@ -1276,8 +1276,6 @@ void RE_engine_gpu_context_destroy(RenderEngine *engine) return; } - BLI_assert(BLI_thread_is_main()); - const bool drw_state = DRW_opengl_context_release(); WM_opengl_context_activate(engine->gpu_context); diff --git a/source/blender/sequencer/intern/modifier.c b/source/blender/sequencer/intern/modifier.c index b0f2f53396b..b17db8f762e 100644 --- a/source/blender/sequencer/intern/modifier.c +++ b/source/blender/sequencer/intern/modifier.c @@ -598,7 +598,7 @@ static void modifier_color_balance_apply( ColorBalanceInitData init_data; if (!ibuf->rect_float && make_float) { - imb_addrectfloatImBuf(ibuf); + imb_addrectfloatImBuf(ibuf, 4); } init_data.cb = cb; diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c index b7dc0e7035d..fd3b6103b94 100644 --- a/source/blender/sequencer/intern/render.c +++ b/source/blender/sequencer/intern/render.c @@ -134,7 +134,7 @@ void seq_imbuf_to_sequencer_space(Scene *scene, ImBuf *ibuf, bool make_float) /* We perform conversion to a float buffer so we don't worry about * precision loss. */ - imb_addrectfloatImBuf(ibuf); + imb_addrectfloatImBuf(ibuf, 4); IMB_colormanagement_transform_from_byte_threaded(ibuf->rect_float, (unsigned char *)ibuf->rect, ibuf->x, |