Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenkernel/BKE_appdir.h5
-rw-r--r--source/blender/blenkernel/BKE_customdata.h1
-rw-r--r--source/blender/blenkernel/BKE_deform.h58
-rw-r--r--source/blender/blenkernel/BKE_key.h3
-rw-r--r--source/blender/blenkernel/BKE_lib_id.h2
-rw-r--r--source/blender/blenkernel/BKE_mesh.h9
-rw-r--r--source/blender/blenkernel/BKE_mesh_legacy_convert.h9
-rw-r--r--source/blender/blenkernel/BKE_node.h9
-rw-r--r--source/blender/blenkernel/BKE_subdiv_mesh.h8
-rw-r--r--source/blender/blenkernel/CMakeLists.txt4
-rw-r--r--source/blender/blenkernel/intern/appdir.c65
-rw-r--r--source/blender/blenkernel/intern/customdata.cc30
-rw-r--r--source/blender/blenkernel/intern/data_transfer.c67
-rw-r--r--source/blender/blenkernel/intern/deform.c170
-rw-r--r--source/blender/blenkernel/intern/key.c10
-rw-r--r--source/blender/blenkernel/intern/mball_tessellate.c1
-rw-r--r--source/blender/blenkernel/intern/mesh.cc6
-rw-r--r--source/blender/blenkernel/intern/mesh_boolean_convert.cc2
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.cc284
-rw-r--r--source/blender/blenkernel/intern/mesh_debug.cc6
-rw-r--r--source/blender/blenkernel/intern/mesh_legacy_convert.cc61
-rw-r--r--source/blender/blenkernel/intern/mesh_mirror.c6
-rw-r--r--source/blender/blenkernel/intern/mesh_tangent.cc2
-rw-r--r--source/blender/blenkernel/intern/multires_unsubdivide.c2
-rw-r--r--source/blender/blenkernel/intern/node.cc6
-rw-r--r--source/blender/blenkernel/intern/subdiv_mesh.cc83
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c4
-rw-r--r--source/blender/blenlib/BLI_bit_vector.hh2
-rw-r--r--source/blender/blenlib/BLI_float3x3.hh16
-rw-r--r--source/blender/blenlib/BLI_math_matrix.h2
-rw-r--r--source/blender/blenlib/BLI_path_util.h10
-rw-r--r--source/blender/blenlib/intern/math_matrix.c6
-rw-r--r--source/blender/blenlib/intern/path_util.c81
-rw-r--r--source/blender/blenlib/tests/BLI_bit_vector_test.cc2
-rw-r--r--source/blender/blenlib/tests/BLI_float3x3_test.cc16
-rw-r--r--source/blender/blenloader/intern/readfile.c10
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_convert.cc63
-rw-r--r--source/blender/compositor/nodes/COM_ScaleNode.cc13
-rw-r--r--source/blender/compositor/operations/COM_SMAAOperation.cc2
-rw-r--r--source/blender/compositor/realtime_compositor/intern/compile_state.cc5
-rw-r--r--source/blender/compositor/realtime_compositor/intern/operation.cc5
-rw-r--r--source/blender/compositor/realtime_compositor/intern/utilities.cc1
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightcache.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h2
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_data.c2
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.c2
-rw-r--r--source/blender/draw/intern/draw_cache_impl_subdivision.cc33
-rw-r--r--source/blender/draw/intern/draw_command.hh2
-rw-r--r--source/blender/draw/intern/draw_manager.hh1
-rw-r--r--source/blender/draw/intern/draw_resource.hh5
-rw-r--r--source/blender/draw/intern/draw_view.cc16
-rw-r--r--source/blender/draw/intern/shaders/draw_resource_finalize_comp.glsl2
-rw-r--r--source/blender/draw/intern/shaders/draw_visibility_comp.glsl2
-rw-r--r--source/blender/editors/interface/interface_drag.cc2
-rw-r--r--source/blender/editors/mesh/editmesh_mask_extract.c6
-rw-r--r--source/blender/editors/mesh/editmesh_path.c5
-rw-r--r--source/blender/editors/mesh/mesh_data.cc142
-rw-r--r--source/blender/editors/mesh/mesh_intern.h4
-rw-r--r--source/blender/editors/mesh/mesh_ops.c4
-rw-r--r--source/blender/editors/mesh/meshtools.cc2
-rw-r--r--source/blender/editors/object/object_add.cc2
-rw-r--r--source/blender/editors/object/object_modifier.cc2
-rw-r--r--source/blender/editors/object/object_remesh.cc4
-rw-r--r--source/blender/editors/object/object_vgroup.cc8
-rw-r--r--source/blender/editors/render/render_preview.cc46
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_density.cc9
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c3
-rw-r--r--source/blender/editors/space_node/link_drag_search.cc2
-rw-r--r--source/blender/editors/space_node/node_relationships.cc45
-rw-r--r--source/blender/editors/space_node/node_select.cc40
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.cc2
-rw-r--r--source/blender/editors/space_view3d/view3d_buttons.c8
-rw-r--r--source/blender/editors/transform/transform_convert_mesh_edge.c4
-rw-r--r--source/blender/editors/transform/transform_convert_mesh_vert_cdata.c4
-rw-r--r--source/blender/geometry/intern/mesh_merge_by_distance.cc9
-rw-r--r--source/blender/gpu/CMakeLists.txt7
-rw-r--r--source/blender/gpu/metal/kernels/gpu_shader_fullscreen_blit_info.hh2
-rw-r--r--source/blender/gpu/metal/mtl_index_buffer.hh1
-rw-r--r--source/blender/gpu/metal/mtl_index_buffer.mm2
-rw-r--r--source/blender/gpu/metal/mtl_primitive.hh2
-rw-r--r--source/blender/gpu/shaders/common/gpu_shader_common_curves.glsl43
-rw-r--r--source/blender/gpu/shaders/compositor/compositor_blur.glsl55
-rw-r--r--source/blender/gpu/shaders/compositor/compositor_symmetric_blur.glsl77
-rw-r--r--source/blender/gpu/shaders/compositor/compositor_symmetric_separable_blur.glsl53
-rw-r--r--source/blender/gpu/shaders/compositor/infos/compositor_blur_info.hh14
-rw-r--r--source/blender/gpu/shaders/compositor/infos/compositor_symmetric_blur_info.hh13
-rw-r--r--source/blender/gpu/shaders/compositor/infos/compositor_symmetric_separable_blur_info.hh14
-rw-r--r--source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_blur_common.glsl32
-rw-r--r--source/blender/io/alembic/intern/abc_reader_mesh.cc12
-rw-r--r--source/blender/io/alembic/intern/abc_reader_points.cc2
-rw-r--r--source/blender/io/collada/MeshImporter.cpp1
-rw-r--r--source/blender/io/usd/intern/usd_reader_mesh.cc6
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_import_mesh.cc6
-rw-r--r--source/blender/makesdna/DNA_gpencil_types.h2
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h2
-rw-r--r--source/blender/makesdna/DNA_meshdata_types.h12
-rw-r--r--source/blender/makesdna/DNA_node_types.h15
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c57
-rw-r--r--source/blender/makesrna/intern/rna_mesh_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c14
-rw-r--r--source/blender/modifiers/intern/MOD_array.c6
-rw-r--r--source/blender/modifiers/intern/MOD_bevel.c4
-rw-r--r--source/blender/modifiers/intern/MOD_solidify_extrude.c56
-rw-r--r--source/blender/modifiers/intern/MOD_solidify_nonmanifold.c71
-rw-r--r--source/blender/nodes/NOD_node_declaration.hh18
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_blur.cc401
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_bokehblur.cc103
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_pixelate.cc29
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_scale.cc149
-rw-r--r--source/blender/python/intern/bpy_app.c39
-rw-r--r--source/blender/render/intern/initrender.cc3
-rw-r--r--source/blender/render/intern/render_result.cc16
-rw-r--r--source/blender/windowmanager/intern/wm_files.c25
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c4
114 files changed, 2019 insertions, 920 deletions
diff --git a/source/blender/blenkernel/BKE_appdir.h b/source/blender/blenkernel/BKE_appdir.h
index 16488bdbf09..dcacc2ca7b3 100644
--- a/source/blender/blenkernel/BKE_appdir.h
+++ b/source/blender/blenkernel/BKE_appdir.h
@@ -105,11 +105,8 @@ void BKE_appdir_app_templates(struct ListBase *templates);
/**
* Initialize path to program executable.
- *
- * \param strict: When true, use `argv0` unmodified (besides making absolute & normalizing).
- * Otherwise other methods may be used to find the program path, including searching `$PATH`.
*/
-void BKE_appdir_program_path_init(const char *argv0, bool strict);
+void BKE_appdir_program_path_init(const char *argv0);
/**
* Path to executable
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index 44a4f4b5395..09d37682b3c 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -640,7 +640,6 @@ enum {
CD_FAKE_CREASE = CD_FAKE | CD_CREASE, /* *sigh*. */
/* Multiple types of mesh elements... */
- CD_FAKE_BWEIGHT = CD_FAKE | CD_BWEIGHT, /* *sigh*. */
CD_FAKE_UV = CD_FAKE |
CD_MLOOPUV, /* UV flag, because we handle both loop's UVs and poly's textures. */
diff --git a/source/blender/blenkernel/BKE_deform.h b/source/blender/blenkernel/BKE_deform.h
index f58a5502788..677a1053826 100644
--- a/source/blender/blenkernel/BKE_deform.h
+++ b/source/blender/blenkernel/BKE_deform.h
@@ -52,14 +52,22 @@ struct bDeformGroup *BKE_object_defgroup_find_name(const struct Object *ob, cons
/**
* \note caller must free.
*/
-int *BKE_object_defgroup_flip_map(const struct Object *ob, int *flip_map_len, bool use_default);
+int *BKE_object_defgroup_flip_map(const struct Object *ob, bool use_default, int *r_flip_map_num);
+
+/**
+ * Returns flip map for only unlocked defgroups.
+ * \note caller must free.
+ */
+int *BKE_object_defgroup_flip_map_unlocked(const struct Object *ob,
+ bool use_default,
+ int *r_flip_map_num);
/**
* \note caller must free.
*/
int *BKE_object_defgroup_flip_map_single(const struct Object *ob,
- int *flip_map_len,
bool use_default,
- int defgroup);
+ int defgroup,
+ int *r_flip_map_num);
int BKE_object_defgroup_flip_index(const struct Object *ob, int index, bool use_default);
int BKE_object_defgroup_name_index(const struct Object *ob, const char *name);
void BKE_object_defgroup_unique_name(struct bDeformGroup *dg, struct Object *ob);
@@ -112,7 +120,7 @@ float BKE_defvert_array_find_weight_safe(const struct MDeformVert *dvert, int in
* \return The total weight in all groups marked in the selection mask.
*/
float BKE_defvert_total_selected_weight(const struct MDeformVert *dv,
- int defbase_tot,
+ int defbase_num,
const bool *defbase_sel);
/**
@@ -124,9 +132,9 @@ float BKE_defvert_total_selected_weight(const struct MDeformVert *dv,
* commutative with the collective weight function.
*/
float BKE_defvert_multipaint_collective_weight(const struct MDeformVert *dv,
- int defbase_tot,
+ int defbase_num,
const bool *defbase_sel,
- int defbase_tot_sel,
+ int defbase_sel_num,
bool is_normalized);
/* This much unlocked weight is considered equivalent to none. */
@@ -147,7 +155,7 @@ float BKE_defvert_calc_lock_relative_weight(float weight,
*/
float BKE_defvert_lock_relative_weight(float weight,
const struct MDeformVert *dv,
- int defbase_tot,
+ int defbase_num,
const bool *defbase_locked,
const bool *defbase_unlocked);
@@ -160,7 +168,7 @@ void BKE_defvert_copy(struct MDeformVert *dvert_dst, const struct MDeformVert *d
void BKE_defvert_copy_subset(struct MDeformVert *dvert_dst,
const struct MDeformVert *dvert_src,
const bool *vgroup_subset,
- int vgroup_tot);
+ int vgroup_num);
/**
* Overwrite weights filtered by vgroup_subset and with mirroring specified by the flip map
* - do nothing if neither are set.
@@ -169,9 +177,9 @@ void BKE_defvert_copy_subset(struct MDeformVert *dvert_dst,
void BKE_defvert_mirror_subset(struct MDeformVert *dvert_dst,
const struct MDeformVert *dvert_src,
const bool *vgroup_subset,
- int vgroup_tot,
+ int vgroup_num,
const int *flip_map,
- int flip_map_len);
+ int flip_map_num);
/**
* Copy an index from one #MDeformVert to another.
* - do nothing if neither are set.
@@ -194,43 +202,43 @@ void BKE_defvert_sync(struct MDeformVert *dvert_dst,
void BKE_defvert_sync_mapped(struct MDeformVert *dvert_dst,
const struct MDeformVert *dvert_src,
const int *flip_map,
- int flip_map_len,
+ int flip_map_num,
bool use_ensure);
/**
* be sure all flip_map values are valid
*/
void BKE_defvert_remap(struct MDeformVert *dvert, const int *map, int map_len);
-void BKE_defvert_flip(struct MDeformVert *dvert, const int *flip_map, int flip_map_len);
-void BKE_defvert_flip_merged(struct MDeformVert *dvert, const int *flip_map, int flip_map_len);
+void BKE_defvert_flip(struct MDeformVert *dvert, const int *flip_map, int flip_map_num);
+void BKE_defvert_flip_merged(struct MDeformVert *dvert, const int *flip_map, int flip_map_num);
void BKE_defvert_normalize(struct MDeformVert *dvert);
/**
* Same as #BKE_defvert_normalize but takes a bool array.
*/
void BKE_defvert_normalize_subset(struct MDeformVert *dvert,
const bool *vgroup_subset,
- int vgroup_tot);
+ int vgroup_num);
/**
* Same as BKE_defvert_normalize() if the locked vgroup is not a member of the subset
*/
void BKE_defvert_normalize_lock_single(struct MDeformVert *dvert,
const bool *vgroup_subset,
- int vgroup_tot,
+ int vgroup_num,
uint def_nr_lock);
/**
* Same as BKE_defvert_normalize() if no locked vgroup is a member of the subset
*/
void BKE_defvert_normalize_lock_map(struct MDeformVert *dvert,
const bool *vgroup_subset,
- int vgroup_tot,
+ int vgroup_num,
const bool *lock_flags,
- int defbase_tot);
+ int defbase_num);
/* Utilities to 'extract' a given vgroup into a simple float array,
* for verts, but also edges/polys/loops. */
void BKE_defvert_extract_vgroup_to_vertweights(const struct MDeformVert *dvert,
int defgroup,
- int num_verts,
+ int verts_num,
bool invert_vgroup,
float *r_weights);
/**
@@ -239,25 +247,25 @@ void BKE_defvert_extract_vgroup_to_vertweights(const struct MDeformVert *dvert,
*/
void BKE_defvert_extract_vgroup_to_edgeweights(const struct MDeformVert *dvert,
int defgroup,
- int num_verts,
+ int verts_num,
const struct MEdge *edges,
- int num_edges,
+ int edges_num,
bool invert_vgroup,
float *r_weights);
void BKE_defvert_extract_vgroup_to_loopweights(const struct MDeformVert *dvert,
int defgroup,
- int num_verts,
+ int verts_num,
const struct MLoop *loops,
- int num_loops,
+ int loops_num,
bool invert_vgroup,
float *r_weights);
void BKE_defvert_extract_vgroup_to_polyweights(const struct MDeformVert *dvert,
int defgroup,
- int num_verts,
+ int verts_num,
const struct MLoop *loops,
- int num_loops,
+ int loops_num,
const struct MPoly *polys,
- int num_polys,
+ int polys_num,
bool invert_vgroup,
float *r_weights);
diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h
index 9f506ded8e9..45a72e8d7a3 100644
--- a/source/blender/blenkernel/BKE_key.h
+++ b/source/blender/blenkernel/BKE_key.h
@@ -95,6 +95,9 @@ struct KeyBlock *BKE_keyblock_from_key(struct Key *key, int index);
* Get the appropriate #KeyBlock given a name to search for.
*/
struct KeyBlock *BKE_keyblock_find_name(struct Key *key, const char name[]);
+
+struct KeyBlock *BKE_keyblock_find_uid(struct Key *key, int uid);
+
/**
* \brief copy shape-key attributes, but not key data or name/UID.
*/
diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h
index 4e4b393fcd6..e5b013ce201 100644
--- a/source/blender/blenkernel/BKE_lib_id.h
+++ b/source/blender/blenkernel/BKE_lib_id.h
@@ -623,7 +623,7 @@ bool BKE_id_can_be_asset(const struct ID *id);
/**
* Return the owner ID of the given `id`, if any.
*
- * \note: This will only return non-NULL for embedded IDs (master collections etc.), and shapekeys.
+ * \note This will only return non-NULL for embedded IDs (master collections etc.), and shape-keys.
*/
struct ID *BKE_id_owner_get(struct ID *id);
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index 1048ca39958..ef57c9a2e0e 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -292,13 +292,10 @@ struct Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph,
bool build_shapekey_layers);
/**
- * Copies a nomain-Mesh into an existing Mesh.
+ * Move data from a mesh outside of the main data-base into a mesh in the data-base.
+ * Takes ownership of the source mesh.
*/
-void BKE_mesh_nomain_to_mesh(struct Mesh *mesh_src,
- struct Mesh *mesh_dst,
- struct Object *ob,
- const struct CustomData_MeshMasks *mask,
- bool take_ownership);
+void BKE_mesh_nomain_to_mesh(struct Mesh *mesh_src, struct Mesh *mesh_dst, struct Object *ob);
void BKE_mesh_nomain_to_meshkey(struct Mesh *mesh_src, struct Mesh *mesh_dst, struct KeyBlock *kb);
/* vertex level transformations & checks (no derived mesh) */
diff --git a/source/blender/blenkernel/BKE_mesh_legacy_convert.h b/source/blender/blenkernel/BKE_mesh_legacy_convert.h
index 11ee86c62a7..e67aec0b9ce 100644
--- a/source/blender/blenkernel/BKE_mesh_legacy_convert.h
+++ b/source/blender/blenkernel/BKE_mesh_legacy_convert.h
@@ -18,6 +18,15 @@ struct Mesh;
struct MFace;
/**
+ * Copy bevel weights from separate layers into vertices and edges.
+ */
+void BKE_mesh_legacy_bevel_weight_from_layers(struct Mesh *mesh);
+/**
+ * Copy bevel weights from vertices and edges to separate layers.
+ */
+void BKE_mesh_legacy_bevel_weight_to_layers(struct Mesh *mesh);
+
+/**
* Convert the hidden element attributes to the old flag format for writing.
*/
void BKE_mesh_legacy_convert_hide_layers_to_flags(struct Mesh *mesh);
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 46303a4e19c..55bf24f943e 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -1337,15 +1337,6 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
#define CMP_CHAN_RGB 1
#define CMP_CHAN_A 2
-/* scale node type, in custom1 */
-#define CMP_SCALE_RELATIVE 0
-#define CMP_SCALE_ABSOLUTE 1
-#define CMP_SCALE_SCENEPERCENT 2
-#define CMP_SCALE_RENDERPERCENT 3
-/* custom2 */
-#define CMP_SCALE_RENDERSIZE_FRAME_ASPECT (1 << 0)
-#define CMP_SCALE_RENDERSIZE_FRAME_CROP (1 << 1)
-
/* track position node, in custom1 */
#define CMP_TRACKPOS_ABSOLUTE 0
#define CMP_TRACKPOS_RELATIVE_START 1
diff --git a/source/blender/blenkernel/BKE_subdiv_mesh.h b/source/blender/blenkernel/BKE_subdiv_mesh.h
index b24db517143..49c45efafe0 100644
--- a/source/blender/blenkernel/BKE_subdiv_mesh.h
+++ b/source/blender/blenkernel/BKE_subdiv_mesh.h
@@ -14,7 +14,9 @@ extern "C" {
#endif
struct Mesh;
+struct MeshElemMap;
struct MEdge;
+struct MVert;
struct Subdiv;
typedef struct SubdivToMeshSettings {
@@ -37,8 +39,10 @@ struct Mesh *BKE_subdiv_to_mesh(struct Subdiv *subdiv,
/* Interpolate a position along the `coarse_edge` at the relative `u` coordinate. If `is_simple` is
* false, this will perform a B-Spline interpolation using the edge neighbors, otherwise a linear
* interpolation will be done base on the edge vertices. */
-void BKE_subdiv_mesh_interpolate_position_on_edge(const struct Mesh *coarse_mesh,
- const struct MEdge *coarse_edge,
+void BKE_subdiv_mesh_interpolate_position_on_edge(const struct MVert *coarse_verts,
+ const struct MEdge *coarse_edges,
+ const struct MeshElemMap *vert_to_edge_map,
+ int coarse_edge_index,
bool is_simple,
float u,
float pos_r[3]);
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 9521da8417e..b982c69a378 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -659,6 +659,10 @@ if(WITH_PYTHON)
)
add_definitions(-DWITH_PYTHON)
+ if(WITH_PYTHON_MODULE)
+ add_definitions(-DWITH_PYTHON_MODULE)
+ endif()
+
if(WITH_PYTHON_SAFETY)
add_definitions(-DWITH_PYTHON_SAFETY)
endif()
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index c19afdb4fb8..f4dec0aecd7 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -374,7 +374,7 @@ static bool get_path_local_ex(char *targetpath,
/* Try `{g_app.program_dirname}/2.xx/{folder_name}` the default directory
* for a portable distribution. See `WITH_INSTALL_PORTABLE` build-option. */
const char *path_base = g_app.program_dirname;
-#ifdef __APPLE__
+#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];
@@ -782,6 +782,7 @@ const char *BKE_appdir_folder_id_version(const int folder_id,
* Access locations of Blender & Python.
* \{ */
+#ifndef WITH_PYTHON_MODULE
/**
* Checks if name is a fully qualified filename to an executable.
* If not it searches `$PATH` for the file. On Windows it also
@@ -794,11 +795,11 @@ const char *BKE_appdir_folder_id_version(const int folder_id,
* (must be #FILE_MAX minimum)
* \param name: The name of the executable (usually `argv[0]`) to be checked
*/
-static void where_am_i(char *fullname, const size_t maxlen, const char *name, const bool strict)
+static void where_am_i(char *fullname, const size_t maxlen, const char *name)
{
-#ifdef WITH_BINRELOC
+# ifdef WITH_BINRELOC
/* Linux uses `binreloc` since `argv[0]` is not reliable, call `br_init(NULL)` first. */
- if (!strict) {
+ {
const char *path = NULL;
path = br_find_exe(NULL);
if (path) {
@@ -807,10 +808,10 @@ static void where_am_i(char *fullname, const size_t maxlen, const char *name, co
return;
}
}
-#endif
+# endif
-#ifdef _WIN32
- if (!strict) {
+# ifdef _WIN32
+ {
wchar_t *fullname_16 = MEM_mallocN(maxlen * sizeof(wchar_t), "ProgramPath");
if (GetModuleFileNameW(0, fullname_16, maxlen)) {
conv_utf_16_to_8(fullname_16, fullname, maxlen);
@@ -825,7 +826,7 @@ static void where_am_i(char *fullname, const size_t maxlen, const char *name, co
MEM_freeN(fullname_16);
}
-#endif
+# endif
/* Unix and non Linux. */
if (name && name[0]) {
@@ -833,46 +834,60 @@ static void where_am_i(char *fullname, const size_t maxlen, const char *name, co
BLI_strncpy(fullname, name, maxlen);
if (name[0] == '.') {
BLI_path_abs_from_cwd(fullname, maxlen);
-#ifdef _WIN32
- if (!strict) {
- BLI_path_program_extensions_add_win32(fullname, maxlen);
- }
-#endif
+# ifdef _WIN32
+ BLI_path_program_extensions_add_win32(fullname, maxlen);
+# endif
}
else if (BLI_path_slash_rfind(name)) {
/* Full path. */
BLI_strncpy(fullname, name, maxlen);
-#ifdef _WIN32
- if (!strict) {
- BLI_path_program_extensions_add_win32(fullname, maxlen);
- }
-#endif
+# ifdef _WIN32
+ BLI_path_program_extensions_add_win32(fullname, maxlen);
+# endif
}
else {
- if (!strict) {
- BLI_path_program_search(fullname, maxlen, name);
- }
+ BLI_path_program_search(fullname, maxlen, name);
}
/* Remove "/./" and "/../" so string comparisons can be used on the path. */
BLI_path_normalize(NULL, fullname);
-#if defined(DEBUG)
+# if defined(DEBUG)
if (!STREQ(name, fullname)) {
CLOG_INFO(&LOG, 2, "guessing '%s' == '%s'", name, fullname);
}
-#endif
+# endif
}
}
+#endif /* WITH_PYTHON_MODULE */
-void BKE_appdir_program_path_init(const char *argv0, const bool strict)
+void BKE_appdir_program_path_init(const char *argv0)
{
- where_am_i(g_app.program_filepath, sizeof(g_app.program_filepath), argv0, strict);
+#ifdef WITH_PYTHON_MODULE
+ /* NOTE(@campbellbarton): Always use `argv[0]` as is, when building as a Python module.
+ * Otherwise other methods of detecting the binary that override this argument
+ * which must point to the Python module for data-files to be detected. */
+ STRNCPY(g_app.program_filepath, argv0);
+ BLI_path_abs_from_cwd(g_app.program_filepath, sizeof(g_app.program_filepath));
+ BLI_path_normalize(NULL, g_app.program_filepath);
+
+ if (g_app.program_dirname[0] == '\0') {
+ /* First time initializing, the file binary path isn't valid from a Python module.
+ * Calling again must set the `filepath` and leave the directory as-is. */
+ BLI_split_dir_part(
+ g_app.program_filepath, g_app.program_dirname, sizeof(g_app.program_dirname));
+ g_app.program_filepath[0] = '\0';
+ }
+#else
+ where_am_i(g_app.program_filepath, sizeof(g_app.program_filepath), argv0);
BLI_split_dir_part(g_app.program_filepath, g_app.program_dirname, sizeof(g_app.program_dirname));
+#endif
}
const char *BKE_appdir_program_path(void)
{
+#ifndef WITH_PYTHON_MODULE /* Default's to empty when building as as Python module. */
BLI_assert(g_app.program_filepath[0]);
+#endif
return g_app.program_filepath;
}
diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc
index cfb8416b0b4..24373053896 100644
--- a/source/blender/blenkernel/intern/customdata.cc
+++ b/source/blender/blenkernel/intern/customdata.cc
@@ -1867,7 +1867,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
/* 28: CD_SHAPEKEY */
{sizeof(float[3]), "", 0, N_("ShapeKey"), nullptr, nullptr, layerInterp_shapekey},
/* 29: CD_BWEIGHT */
- {sizeof(float), "", 0, N_("BevelWeight"), nullptr, nullptr, layerInterp_bweight},
+ {sizeof(MFloatProperty), "MFloatProperty", 1, nullptr, nullptr, nullptr, layerInterp_bweight},
/* 30: CD_CREASE */
/* NOTE: we do not interpolate crease data as it should be either inherited for subdivided
* edges, or for vertex creases, only present on the original vertex. */
@@ -2108,23 +2108,23 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
};
const CustomData_MeshMasks CD_MASK_BAREMESH = {
- /* vmask */ CD_MASK_MVERT | CD_MASK_BWEIGHT,
- /* emask */ CD_MASK_MEDGE | CD_MASK_BWEIGHT,
+ /* vmask */ CD_MASK_MVERT,
+ /* emask */ CD_MASK_MEDGE,
/* fmask */ 0,
/* pmask */ CD_MASK_MPOLY | CD_MASK_FACEMAP,
/* lmask */ CD_MASK_MLOOP,
};
const CustomData_MeshMasks CD_MASK_BAREMESH_ORIGINDEX = {
- /* vmask */ CD_MASK_MVERT | CD_MASK_BWEIGHT | CD_MASK_ORIGINDEX,
- /* emask */ CD_MASK_MEDGE | CD_MASK_BWEIGHT | CD_MASK_ORIGINDEX,
+ /* vmask */ CD_MASK_MVERT | CD_MASK_ORIGINDEX,
+ /* emask */ CD_MASK_MEDGE | CD_MASK_ORIGINDEX,
/* fmask */ 0,
/* pmask */ CD_MASK_MPOLY | CD_MASK_FACEMAP | CD_MASK_ORIGINDEX,
/* lmask */ CD_MASK_MLOOP,
};
const CustomData_MeshMasks CD_MASK_MESH = {
/* vmask */ (CD_MASK_MVERT | CD_MASK_MDEFORMVERT | CD_MASK_MVERT_SKIN | CD_MASK_PAINT_MASK |
- CD_MASK_PROP_ALL | CD_MASK_CREASE),
- /* emask */ (CD_MASK_MEDGE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
+ CD_MASK_PROP_ALL | CD_MASK_CREASE | CD_MASK_BWEIGHT),
+ /* emask */ (CD_MASK_MEDGE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL | CD_MASK_BWEIGHT),
/* fmask */ 0,
/* pmask */
(CD_MASK_MPOLY | CD_MASK_FACEMAP | CD_MASK_FREESTYLE_FACE | CD_MASK_PROP_ALL |
@@ -2136,8 +2136,8 @@ const CustomData_MeshMasks CD_MASK_MESH = {
const CustomData_MeshMasks CD_MASK_DERIVEDMESH = {
/* vmask */ (CD_MASK_ORIGINDEX | CD_MASK_MDEFORMVERT | CD_MASK_SHAPEKEY | CD_MASK_MVERT_SKIN |
CD_MASK_PAINT_MASK | CD_MASK_ORCO | CD_MASK_CLOTH_ORCO | CD_MASK_PROP_ALL |
- CD_MASK_CREASE),
- /* emask */ (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
+ CD_MASK_CREASE | CD_MASK_BWEIGHT),
+ /* emask */ (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_EDGE | CD_MASK_BWEIGHT | CD_MASK_PROP_ALL),
/* fmask */ (CD_MASK_ORIGINDEX | CD_MASK_ORIGSPACE | CD_MASK_PREVIEW_MCOL | CD_MASK_TANGENT),
/* pmask */
(CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | CD_MASK_PROP_ALL |
@@ -2353,8 +2353,16 @@ bool CustomData_merge(const CustomData *source,
changed = true;
if (layer->anonymous_id != nullptr) {
- BKE_anonymous_attribute_id_increment_weak(layer->anonymous_id);
newlayer->anonymous_id = layer->anonymous_id;
+ if (alloctype == CD_ASSIGN) {
+ layer->anonymous_id = nullptr;
+ }
+ else {
+ BKE_anonymous_attribute_id_increment_weak(layer->anonymous_id);
+ }
+ }
+ if (alloctype == CD_ASSIGN) {
+ layer->data = nullptr;
}
}
}
@@ -5167,7 +5175,7 @@ void CustomData_data_transfer(const MeshPairRemap *me_remap,
else {
const LayerTypeInfo *type_info = layerType_getInfo(data_type);
- /* NOTE: we can use 'fake' CDLayers, like e.g. for crease, bweight, etc. :/. */
+ /* NOTE: we can use 'fake' CDLayers for crease :/. */
data_size = (size_t)type_info->size;
data_step = laymap->elem_size ? laymap->elem_size : data_size;
data_offset = laymap->data_offset;
diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c
index 6fbdade08f8..6c7715c625e 100644
--- a/source/blender/blenkernel/intern/data_transfer.c
+++ b/source/blender/blenkernel/intern/data_transfer.c
@@ -192,7 +192,7 @@ int BKE_object_data_transfer_dttype_to_cdtype(const int dtdata_type)
case DT_TYPE_SKIN:
return CD_MVERT_SKIN;
case DT_TYPE_BWEIGHT_VERT:
- return CD_FAKE_BWEIGHT;
+ return CD_BWEIGHT;
case DT_TYPE_SHARP_EDGE:
return CD_FAKE_SHARP;
@@ -201,7 +201,7 @@ int BKE_object_data_transfer_dttype_to_cdtype(const int dtdata_type)
case DT_TYPE_CREASE:
return CD_FAKE_CREASE;
case DT_TYPE_BWEIGHT_EDGE:
- return CD_FAKE_BWEIGHT;
+ return CD_BWEIGHT;
case DT_TYPE_FREESTYLE_EDGE:
return CD_FREESTYLE_EDGE;
@@ -928,38 +928,6 @@ static bool data_transfer_layersmapping_generate(ListBase *r_map,
}
return true;
}
- if (cddata_type == CD_FAKE_BWEIGHT) {
- const size_t elem_size = sizeof(*((MVert *)NULL));
- const size_t data_size = sizeof(((MVert *)NULL)->bweight);
- const size_t data_offset = offsetof(MVert, bweight);
- const uint64_t data_flag = 0;
-
- if (!(me_src->cd_flag & ME_CDFLAG_VERT_BWEIGHT)) {
- if (use_delete) {
- me_dst->cd_flag &= ~ME_CDFLAG_VERT_BWEIGHT;
- }
- return true;
- }
- me_dst->cd_flag |= ME_CDFLAG_VERT_BWEIGHT;
- if (r_map) {
- data_transfer_layersmapping_add_item(r_map,
- cddata_type,
- mix_mode,
- mix_factor,
- mix_weights,
- BKE_mesh_verts(me_src),
- BKE_mesh_verts_for_write(me_dst),
- me_src->totvert,
- me_dst->totvert,
- elem_size,
- data_size,
- data_offset,
- data_flag,
- data_transfer_interp_char,
- interp_data);
- }
- return true;
- }
if (cddata_type == CD_FAKE_MDEFORMVERT) {
bool ret;
@@ -1045,38 +1013,7 @@ static bool data_transfer_layersmapping_generate(ListBase *r_map,
}
return true;
}
- if (cddata_type == CD_FAKE_BWEIGHT) {
- const size_t elem_size = sizeof(*((MEdge *)NULL));
- const size_t data_size = sizeof(((MEdge *)NULL)->bweight);
- const size_t data_offset = offsetof(MEdge, bweight);
- const uint64_t data_flag = 0;
- if (!(me_src->cd_flag & ME_CDFLAG_EDGE_BWEIGHT)) {
- if (use_delete) {
- me_dst->cd_flag &= ~ME_CDFLAG_EDGE_BWEIGHT;
- }
- return true;
- }
- me_dst->cd_flag |= ME_CDFLAG_EDGE_BWEIGHT;
- if (r_map) {
- data_transfer_layersmapping_add_item(r_map,
- cddata_type,
- mix_mode,
- mix_factor,
- mix_weights,
- BKE_mesh_edges(me_src),
- BKE_mesh_edges_for_write(me_dst),
- me_src->totedge,
- me_dst->totedge,
- elem_size,
- data_size,
- data_offset,
- data_flag,
- data_transfer_interp_char,
- interp_data);
- }
- return true;
- }
if (r_map && ELEM(cddata_type, CD_FAKE_SHARP, CD_FAKE_SEAM)) {
const size_t elem_size = sizeof(*((MEdge *)NULL));
const size_t data_size = sizeof(((MEdge *)NULL)->flag);
diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c
index f928079f3ea..7940d65b1bb 100644
--- a/source/blender/blenkernel/intern/deform.c
+++ b/source/blender/blenkernel/intern/deform.c
@@ -94,10 +94,10 @@ bDeformGroup *BKE_defgroup_duplicate(const bDeformGroup *ingroup)
void BKE_defvert_copy_subset(MDeformVert *dvert_dst,
const MDeformVert *dvert_src,
const bool *vgroup_subset,
- const int vgroup_tot)
+ const int vgroup_num)
{
int defgroup;
- for (defgroup = 0; defgroup < vgroup_tot; defgroup++) {
+ for (defgroup = 0; defgroup < vgroup_num; defgroup++) {
if (vgroup_subset[defgroup]) {
BKE_defvert_copy_index(dvert_dst, defgroup, dvert_src, defgroup);
}
@@ -107,12 +107,12 @@ void BKE_defvert_copy_subset(MDeformVert *dvert_dst,
void BKE_defvert_mirror_subset(MDeformVert *dvert_dst,
const MDeformVert *dvert_src,
const bool *vgroup_subset,
- const int vgroup_tot,
+ const int vgroup_num,
const int *flip_map,
- const int flip_map_len)
+ const int flip_map_num)
{
int defgroup;
- for (defgroup = 0; defgroup < vgroup_tot && defgroup < flip_map_len; defgroup++) {
+ for (defgroup = 0; defgroup < vgroup_num && defgroup < flip_map_num; defgroup++) {
if (vgroup_subset[defgroup] && (dvert_dst != dvert_src || flip_map[defgroup] != defgroup)) {
BKE_defvert_copy_index(dvert_dst, flip_map[defgroup], dvert_src, defgroup);
}
@@ -189,13 +189,13 @@ void BKE_defvert_sync(MDeformVert *dvert_dst, const MDeformVert *dvert_src, cons
void BKE_defvert_sync_mapped(MDeformVert *dvert_dst,
const MDeformVert *dvert_src,
const int *flip_map,
- const int flip_map_len,
+ const int flip_map_num,
const bool use_ensure)
{
if (dvert_src->totweight && dvert_dst->totweight) {
MDeformWeight *dw_src = dvert_src->dw;
for (int i = 0; i < dvert_src->totweight; i++, dw_src++) {
- if (dw_src->def_nr < flip_map_len) {
+ if (dw_src->def_nr < flip_map_num) {
MDeformWeight *dw_dst;
if (use_ensure) {
dw_dst = BKE_defvert_ensure_index(dvert_dst, flip_map[dw_src->def_nr]);
@@ -226,14 +226,14 @@ void BKE_defvert_remap(MDeformVert *dvert, const int *map, const int map_len)
void BKE_defvert_normalize_subset(MDeformVert *dvert,
const bool *vgroup_subset,
- const int vgroup_tot)
+ const int vgroup_num)
{
if (dvert->totweight == 0) {
/* nothing */
}
else if (dvert->totweight == 1) {
MDeformWeight *dw = dvert->dw;
- if ((dw->def_nr < vgroup_tot) && vgroup_subset[dw->def_nr]) {
+ if ((dw->def_nr < vgroup_num) && vgroup_subset[dw->def_nr]) {
dw->weight = 1.0f;
}
}
@@ -241,7 +241,7 @@ void BKE_defvert_normalize_subset(MDeformVert *dvert,
MDeformWeight *dw = dvert->dw;
float tot_weight = 0.0f;
for (int i = dvert->totweight; i != 0; i--, dw++) {
- if ((dw->def_nr < vgroup_tot) && vgroup_subset[dw->def_nr]) {
+ if ((dw->def_nr < vgroup_num) && vgroup_subset[dw->def_nr]) {
tot_weight += dw->weight;
}
}
@@ -250,7 +250,7 @@ void BKE_defvert_normalize_subset(MDeformVert *dvert,
float scalar = 1.0f / tot_weight;
dw = dvert->dw;
for (int i = dvert->totweight; i != 0; i--, dw++) {
- if ((dw->def_nr < vgroup_tot) && vgroup_subset[dw->def_nr]) {
+ if ((dw->def_nr < vgroup_num) && vgroup_subset[dw->def_nr]) {
dw->weight *= scalar;
/* in case of division errors with very low weights */
@@ -292,7 +292,7 @@ void BKE_defvert_normalize(MDeformVert *dvert)
void BKE_defvert_normalize_lock_single(MDeformVert *dvert,
const bool *vgroup_subset,
- const int vgroup_tot,
+ const int vgroup_num,
const uint def_nr_lock)
{
if (dvert->totweight == 0) {
@@ -300,7 +300,7 @@ void BKE_defvert_normalize_lock_single(MDeformVert *dvert,
}
else if (dvert->totweight == 1) {
MDeformWeight *dw = dvert->dw;
- if ((dw->def_nr < vgroup_tot) && vgroup_subset[dw->def_nr]) {
+ if ((dw->def_nr < vgroup_num) && vgroup_subset[dw->def_nr]) {
if (def_nr_lock != dw->def_nr) {
dw->weight = 1.0f;
}
@@ -314,7 +314,7 @@ void BKE_defvert_normalize_lock_single(MDeformVert *dvert,
float lock_iweight = 1.0f;
for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
- if ((dw->def_nr < vgroup_tot) && vgroup_subset[dw->def_nr]) {
+ if ((dw->def_nr < vgroup_num) && vgroup_subset[dw->def_nr]) {
if (dw->def_nr != def_nr_lock) {
tot_weight += dw->weight;
}
@@ -331,7 +331,7 @@ void BKE_defvert_normalize_lock_single(MDeformVert *dvert,
float scalar = (1.0f / tot_weight) * lock_iweight;
for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
- if ((dw->def_nr < vgroup_tot) && vgroup_subset[dw->def_nr]) {
+ if ((dw->def_nr < vgroup_num) && vgroup_subset[dw->def_nr]) {
if (dw != dw_lock) {
dw->weight *= scalar;
@@ -346,17 +346,17 @@ void BKE_defvert_normalize_lock_single(MDeformVert *dvert,
void BKE_defvert_normalize_lock_map(MDeformVert *dvert,
const bool *vgroup_subset,
- const int vgroup_tot,
+ const int vgroup_num,
const bool *lock_flags,
- const int defbase_tot)
+ const int defbase_num)
{
if (dvert->totweight == 0) {
/* nothing */
}
else if (dvert->totweight == 1) {
MDeformWeight *dw = dvert->dw;
- if ((dw->def_nr < vgroup_tot) && vgroup_subset[dw->def_nr]) {
- if ((dw->def_nr < defbase_tot) && (lock_flags[dw->def_nr] == false)) {
+ if ((dw->def_nr < vgroup_num) && vgroup_subset[dw->def_nr]) {
+ if ((dw->def_nr < defbase_num) && (lock_flags[dw->def_nr] == false)) {
dw->weight = 1.0f;
}
}
@@ -368,8 +368,8 @@ void BKE_defvert_normalize_lock_map(MDeformVert *dvert,
float lock_iweight = 0.0f;
for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
- if ((dw->def_nr < vgroup_tot) && vgroup_subset[dw->def_nr]) {
- if ((dw->def_nr < defbase_tot) && (lock_flags[dw->def_nr] == false)) {
+ if ((dw->def_nr < vgroup_num) && vgroup_subset[dw->def_nr]) {
+ if ((dw->def_nr < defbase_num) && (lock_flags[dw->def_nr] == false)) {
tot_weight += dw->weight;
}
else {
@@ -386,8 +386,8 @@ void BKE_defvert_normalize_lock_map(MDeformVert *dvert,
float scalar = (1.0f / tot_weight) * lock_iweight;
for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
- if ((dw->def_nr < vgroup_tot) && vgroup_subset[dw->def_nr]) {
- if ((dw->def_nr < defbase_tot) && (lock_flags[dw->def_nr] == false)) {
+ if ((dw->def_nr < vgroup_num) && vgroup_subset[dw->def_nr]) {
+ if ((dw->def_nr < defbase_num) && (lock_flags[dw->def_nr] == false)) {
dw->weight *= scalar;
/* in case of division errors with very low weights */
@@ -399,13 +399,13 @@ void BKE_defvert_normalize_lock_map(MDeformVert *dvert,
}
}
-void BKE_defvert_flip(MDeformVert *dvert, const int *flip_map, const int flip_map_len)
+void BKE_defvert_flip(MDeformVert *dvert, const int *flip_map, const int flip_map_num)
{
MDeformWeight *dw;
int i;
for (dw = dvert->dw, i = 0; i < dvert->totweight; dw++, i++) {
- if (dw->def_nr < flip_map_len) {
+ if (dw->def_nr < flip_map_num) {
if (flip_map[dw->def_nr] >= 0) {
dw->def_nr = flip_map[dw->def_nr];
}
@@ -413,7 +413,7 @@ void BKE_defvert_flip(MDeformVert *dvert, const int *flip_map, const int flip_ma
}
}
-void BKE_defvert_flip_merged(MDeformVert *dvert, const int *flip_map, const int flip_map_len)
+void BKE_defvert_flip_merged(MDeformVert *dvert, const int *flip_map, const int flip_map_num)
{
MDeformWeight *dw, *dw_cpy;
float weight;
@@ -421,7 +421,7 @@ void BKE_defvert_flip_merged(MDeformVert *dvert, const int *flip_map, const int
/* copy weights */
for (dw = dvert->dw, i = 0; i < totweight; dw++, i++) {
- if (dw->def_nr < flip_map_len) {
+ if (dw->def_nr < flip_map_num) {
if (flip_map[dw->def_nr] >= 0) {
/* error checkers complain of this but we'll never get NULL return */
dw_cpy = BKE_defvert_ensure_index(dvert, flip_map[dw->def_nr]);
@@ -572,20 +572,25 @@ void BKE_object_defgroup_active_index_set(Object *ob, const int new_index)
*index = new_index;
}
-int *BKE_object_defgroup_flip_map(const Object *ob, int *flip_map_len, const bool use_default)
+static int *object_defgroup_unlocked_flip_map_ex(const Object *ob,
+ const bool use_default,
+ const bool use_only_unlocked,
+ int *r_flip_map_num)
{
const ListBase *defbase = BKE_object_defgroup_list(ob);
- int defbase_tot = *flip_map_len = BLI_listbase_count(defbase);
+ const int defbase_num = BLI_listbase_count(defbase);
+ *r_flip_map_num = defbase_num;
- if (defbase_tot == 0) {
+ if (defbase_num == 0) {
return NULL;
}
bDeformGroup *dg;
char name_flip[sizeof(dg->name)];
- int i, flip_num, *map = MEM_mallocN(defbase_tot * sizeof(int), __func__);
+ int i, flip_num;
+ int *map = MEM_mallocN(defbase_num * sizeof(int), __func__);
- for (i = 0; i < defbase_tot; i++) {
+ for (i = 0; i < defbase_num; i++) {
map[i] = -1;
}
@@ -597,11 +602,15 @@ int *BKE_object_defgroup_flip_map(const Object *ob, int *flip_map_len, const boo
map[i] = i;
}
+ if (use_only_unlocked && (dg->flag & DG_LOCK_WEIGHT)) {
+ continue;
+ }
+
BLI_string_flip_side_name(name_flip, dg->name, false, sizeof(name_flip));
if (!STREQ(name_flip, dg->name)) {
flip_num = BKE_object_defgroup_name_index(ob, name_flip);
- if (flip_num >= 0) {
+ if (flip_num != -1) {
map[i] = flip_num;
map[flip_num] = i; /* save an extra lookup */
}
@@ -611,23 +620,36 @@ int *BKE_object_defgroup_flip_map(const Object *ob, int *flip_map_len, const boo
return map;
}
+int *BKE_object_defgroup_flip_map(const Object *ob, const bool use_default, int *r_flip_map_num)
+{
+ return object_defgroup_unlocked_flip_map_ex(ob, use_default, false, r_flip_map_num);
+}
+
+int *BKE_object_defgroup_flip_map_unlocked(const Object *ob,
+ const bool use_default,
+ int *r_flip_map_num)
+{
+ return object_defgroup_unlocked_flip_map_ex(ob, use_default, true, r_flip_map_num);
+}
+
int *BKE_object_defgroup_flip_map_single(const Object *ob,
- int *flip_map_len,
const bool use_default,
- int defgroup)
+ const int defgroup,
+ int *r_flip_map_num)
{
const ListBase *defbase = BKE_object_defgroup_list(ob);
- int defbase_tot = *flip_map_len = BLI_listbase_count(defbase);
+ const int defbase_num = BLI_listbase_count(defbase);
+ *r_flip_map_num = defbase_num;
- if (defbase_tot == 0) {
+ if (defbase_num == 0) {
return NULL;
}
bDeformGroup *dg;
char name_flip[sizeof(dg->name)];
- int i, flip_num, *map = MEM_mallocN(defbase_tot * sizeof(int), __func__);
+ int i, flip_num, *map = MEM_mallocN(defbase_num * sizeof(int), __func__);
- for (i = 0; i < defbase_tot; i++) {
+ for (i = 0; i < defbase_num; i++) {
map[i] = use_default ? i : -1;
}
@@ -776,7 +798,7 @@ MDeformWeight *BKE_defvert_ensure_index(MDeformVert *dvert, const int defgroup)
return dw_new;
}
-void BKE_defvert_add_index_notest(MDeformVert *dvert, int defgroup, const float weight)
+void BKE_defvert_add_index_notest(MDeformVert *dvert, const int defgroup, const float weight)
{
/* TODO: merge with #BKE_defvert_ensure_index! */
@@ -870,7 +892,7 @@ bool BKE_defvert_is_weight_zero(const struct MDeformVert *dvert, const int defgr
}
float BKE_defvert_total_selected_weight(const struct MDeformVert *dv,
- int defbase_tot,
+ int defbase_num,
const bool *defbase_sel)
{
float total = 0.0f;
@@ -881,7 +903,7 @@ float BKE_defvert_total_selected_weight(const struct MDeformVert *dv,
}
for (int i = dv->totweight; i != 0; i--, dw++) {
- if (dw->def_nr < defbase_tot) {
+ if (dw->def_nr < defbase_num) {
if (defbase_sel[dw->def_nr]) {
total += dw->weight;
}
@@ -892,17 +914,17 @@ float BKE_defvert_total_selected_weight(const struct MDeformVert *dv,
}
float BKE_defvert_multipaint_collective_weight(const struct MDeformVert *dv,
- int defbase_tot,
+ const int defbase_num,
const bool *defbase_sel,
- int defbase_tot_sel,
- bool is_normalized)
+ const int defbase_sel_num,
+ const bool is_normalized)
{
- float total = BKE_defvert_total_selected_weight(dv, defbase_tot, defbase_sel);
+ float total = BKE_defvert_total_selected_weight(dv, defbase_num, defbase_sel);
/* in multipaint, get the average if auto normalize is inactive
* get the sum if it is active */
if (!is_normalized) {
- total /= defbase_tot_sel;
+ total /= defbase_sel_num;
}
return total;
@@ -936,19 +958,19 @@ float BKE_defvert_calc_lock_relative_weight(float weight,
return weight / (1.0f - locked_weight);
}
-float BKE_defvert_lock_relative_weight(float weight,
+float BKE_defvert_lock_relative_weight(const float weight,
const struct MDeformVert *dv,
- int defbase_tot,
+ const int defbase_num,
const bool *defbase_locked,
const bool *defbase_unlocked)
{
- float unlocked = BKE_defvert_total_selected_weight(dv, defbase_tot, defbase_unlocked);
+ float unlocked = BKE_defvert_total_selected_weight(dv, defbase_num, defbase_unlocked);
if (unlocked > 0.0f) {
return weight / unlocked;
}
- float locked = BKE_defvert_total_selected_weight(dv, defbase_tot, defbase_locked);
+ float locked = BKE_defvert_total_selected_weight(dv, defbase_num, defbase_locked);
return BKE_defvert_calc_lock_relative_weight(weight, locked, unlocked);
}
@@ -1010,12 +1032,12 @@ void BKE_defvert_array_free(MDeformVert *dvert, int totvert)
void BKE_defvert_extract_vgroup_to_vertweights(const MDeformVert *dvert,
const int defgroup,
- const int num_verts,
+ const int verts_num,
const bool invert_vgroup,
float *r_weights)
{
if (dvert && defgroup != -1) {
- int i = num_verts;
+ int i = verts_num;
while (i--) {
const float w = BKE_defvert_find_weight(&dvert[i], defgroup);
@@ -1023,24 +1045,24 @@ void BKE_defvert_extract_vgroup_to_vertweights(const MDeformVert *dvert,
}
}
else {
- copy_vn_fl(r_weights, num_verts, invert_vgroup ? 1.0f : 0.0f);
+ copy_vn_fl(r_weights, verts_num, invert_vgroup ? 1.0f : 0.0f);
}
}
void BKE_defvert_extract_vgroup_to_edgeweights(const MDeformVert *dvert,
const int defgroup,
- const int num_verts,
+ const int verts_num,
const MEdge *edges,
- const int num_edges,
+ const int edges_num,
const bool invert_vgroup,
float *r_weights)
{
if (dvert && defgroup != -1) {
- int i = num_edges;
- float *tmp_weights = MEM_mallocN(sizeof(*tmp_weights) * (size_t)num_verts, __func__);
+ int i = edges_num;
+ float *tmp_weights = MEM_mallocN(sizeof(*tmp_weights) * (size_t)verts_num, __func__);
BKE_defvert_extract_vgroup_to_vertweights(
- dvert, defgroup, num_verts, invert_vgroup, tmp_weights);
+ dvert, defgroup, verts_num, invert_vgroup, tmp_weights);
while (i--) {
const MEdge *me = &edges[i];
@@ -1051,24 +1073,24 @@ void BKE_defvert_extract_vgroup_to_edgeweights(const MDeformVert *dvert,
MEM_freeN(tmp_weights);
}
else {
- copy_vn_fl(r_weights, num_edges, 0.0f);
+ copy_vn_fl(r_weights, edges_num, 0.0f);
}
}
void BKE_defvert_extract_vgroup_to_loopweights(const MDeformVert *dvert,
const int defgroup,
- const int num_verts,
+ const int verts_num,
const MLoop *loops,
- const int num_loops,
+ const int loops_num,
const bool invert_vgroup,
float *r_weights)
{
if (dvert && defgroup != -1) {
- int i = num_loops;
- float *tmp_weights = MEM_mallocN(sizeof(*tmp_weights) * (size_t)num_verts, __func__);
+ int i = loops_num;
+ float *tmp_weights = MEM_mallocN(sizeof(*tmp_weights) * (size_t)verts_num, __func__);
BKE_defvert_extract_vgroup_to_vertweights(
- dvert, defgroup, num_verts, invert_vgroup, tmp_weights);
+ dvert, defgroup, verts_num, invert_vgroup, tmp_weights);
while (i--) {
const MLoop *ml = &loops[i];
@@ -1079,26 +1101,26 @@ void BKE_defvert_extract_vgroup_to_loopweights(const MDeformVert *dvert,
MEM_freeN(tmp_weights);
}
else {
- copy_vn_fl(r_weights, num_loops, 0.0f);
+ copy_vn_fl(r_weights, loops_num, 0.0f);
}
}
void BKE_defvert_extract_vgroup_to_polyweights(const MDeformVert *dvert,
const int defgroup,
- const int num_verts,
+ const int verts_num,
const MLoop *loops,
- const int UNUSED(num_loops),
+ const int UNUSED(loops_num),
const MPoly *polys,
- const int num_polys,
+ const int polys_num,
const bool invert_vgroup,
float *r_weights)
{
if (dvert && defgroup != -1) {
- int i = num_polys;
- float *tmp_weights = MEM_mallocN(sizeof(*tmp_weights) * (size_t)num_verts, __func__);
+ int i = polys_num;
+ float *tmp_weights = MEM_mallocN(sizeof(*tmp_weights) * (size_t)verts_num, __func__);
BKE_defvert_extract_vgroup_to_vertweights(
- dvert, defgroup, num_verts, invert_vgroup, tmp_weights);
+ dvert, defgroup, verts_num, invert_vgroup, tmp_weights);
while (i--) {
const MPoly *mp = &polys[i];
@@ -1115,7 +1137,7 @@ void BKE_defvert_extract_vgroup_to_polyweights(const MDeformVert *dvert,
MEM_freeN(tmp_weights);
}
else {
- copy_vn_fl(r_weights, num_polys, 0.0f);
+ copy_vn_fl(r_weights, polys_num, 0.0f);
}
}
@@ -1207,7 +1229,7 @@ static bool data_transfer_layersmapping_vgroups_multisrc_to_dst(ListBase *r_map,
const ListBase *src_list = BKE_object_defgroup_list(ob_src);
ListBase *dst_defbase = BKE_object_defgroup_list_mutable(ob_dst);
- int tot_dst = BLI_listbase_count(dst_defbase);
+ const int tot_dst = BLI_listbase_count(dst_defbase);
const size_t elem_size = sizeof(*((MDeformVert *)NULL));
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index a4475869c2a..2ba81c54872 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -1938,6 +1938,16 @@ KeyBlock *BKE_keyblock_find_name(Key *key, const char name[])
return BLI_findstring(&key->block, name, offsetof(KeyBlock, name));
}
+KeyBlock *BKE_keyblock_find_uid(Key *key, const int uid)
+{
+ LISTBASE_FOREACH (KeyBlock *, kb, &key->block) {
+ if (kb->uid == uid) {
+ return kb;
+ }
+ }
+ return NULL;
+}
+
void BKE_keyblock_copy_settings(KeyBlock *kb_dst, const KeyBlock *kb_src)
{
kb_dst->pos = kb_src->pos;
diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c
index 3917c020759..49963c333ec 100644
--- a/source/blender/blenkernel/intern/mball_tessellate.c
+++ b/source/blender/blenkernel/intern/mball_tessellate.c
@@ -1447,7 +1447,6 @@ Mesh *BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob)
MVert *mvert = CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CONSTRUCT, NULL, mesh->totvert);
for (int i = 0; i < mesh->totvert; i++) {
copy_v3_v3(mvert[i].co, process.co[i]);
- mvert->bweight = 0;
mvert->flag = 0;
}
MEM_freeN(process.co);
diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc
index 8254bb953d2..a5b50824542 100644
--- a/source/blender/blenkernel/intern/mesh.cc
+++ b/source/blender/blenkernel/intern/mesh.cc
@@ -251,6 +251,7 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address
if (!BLO_write_is_undo(writer)) {
BKE_mesh_legacy_convert_hide_layers_to_flags(mesh);
BKE_mesh_legacy_convert_material_indices_to_mpoly(mesh);
+ BKE_mesh_legacy_bevel_weight_from_layers(mesh);
/* When converting to the old mesh format, don't save redundant attributes. */
names_to_skip.add_multiple_new({".hide_vert", ".hide_edge", ".hide_poly"});
@@ -348,6 +349,7 @@ static void mesh_blend_read_data(BlendDataReader *reader, ID *id)
if (!BLO_read_data_is_undo(reader)) {
BKE_mesh_legacy_convert_flags_to_hide_layers(mesh);
BKE_mesh_legacy_convert_mpoly_to_material_indices(mesh);
+ BKE_mesh_legacy_bevel_weight_to_layers(mesh);
}
/* We don't expect to load normals from files, since they are derived data. */
@@ -881,11 +883,12 @@ static void mesh_clear_geometry(Mesh *mesh)
mesh->totpoly = 0;
mesh->act_face = -1;
mesh->totselect = 0;
+
+ BLI_freelistN(&mesh->vertex_group_names);
}
void BKE_mesh_clear_geometry(Mesh *mesh)
{
- BKE_animdata_free(&mesh->id, false);
BKE_mesh_runtime_clear_cache(mesh);
mesh_clear_geometry(mesh);
}
@@ -975,6 +978,7 @@ void BKE_mesh_copy_parameters(Mesh *me_dst, const Mesh *me_src)
copy_v3_v3(me_dst->size, me_src->size);
me_dst->vertex_group_active_index = me_src->vertex_group_active_index;
+ me_dst->attributes_active_index = me_src->attributes_active_index;
}
void BKE_mesh_copy_parameters_for_eval(Mesh *me_dst, const Mesh *me_src)
diff --git a/source/blender/blenkernel/intern/mesh_boolean_convert.cc b/source/blender/blenkernel/intern/mesh_boolean_convert.cc
index 4b08e0b2ed5..7a04e45fe00 100644
--- a/source/blender/blenkernel/intern/mesh_boolean_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_boolean_convert.cc
@@ -381,7 +381,6 @@ static void copy_vert_attributes(Mesh *dest_mesh,
int mv_index,
int index_in_orig_me)
{
- mv->bweight = orig_mv->bweight;
mv->flag = orig_mv->flag;
/* For all layers in the orig mesh, copy the layer information. */
@@ -450,7 +449,6 @@ static void copy_edge_attributes(Mesh *dest_mesh,
int medge_index,
int index_in_orig_me)
{
- medge->bweight = orig_medge->bweight;
medge->crease = orig_medge->crease;
medge->flag = orig_medge->flag;
CustomData *target_cd = &dest_mesh->edata;
diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc
index a8ff90c128a..b7d8972aa7b 100644
--- a/source/blender/blenkernel/intern/mesh_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_convert.cc
@@ -54,9 +54,11 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
+using blender::float3;
using blender::IndexRange;
using blender::MutableSpan;
using blender::Span;
+using blender::StringRefNull;
/* Define for cases when you want extra validation of mesh
* after certain modifications.
@@ -116,7 +118,7 @@ static void make_edges_mdata_extend(Mesh &mesh)
BLI_edgehashIterator_getKey(ehi, &medge->v1, &medge->v2);
BLI_edgehashIterator_setValue(ehi, POINTER_FROM_UINT(e_index));
- medge->crease = medge->bweight = 0;
+ medge->crease = 0;
medge->flag = ME_EDGEDRAW | ME_EDGERENDER;
}
BLI_edgehashIterator_free(ehi);
@@ -1081,7 +1083,7 @@ Mesh *BKE_mesh_new_from_object_to_bmain(Main *bmain,
mesh_in_bmain->smoothresh = mesh->smoothresh;
mesh->mat = nullptr;
- BKE_mesh_nomain_to_mesh(mesh, mesh_in_bmain, nullptr, &CD_MASK_MESH, true);
+ BKE_mesh_nomain_to_mesh(mesh, mesh_in_bmain, nullptr);
/* Anonymous attributes shouldn't exist on original data. */
mesh_in_bmain->attributes_for_write().remove_anonymous();
@@ -1235,239 +1237,113 @@ Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph,
return result;
}
-/* This is a Mesh-based copy of the same function in DerivedMesh.cc */
-static void shapekey_layers_to_keyblocks(Mesh *mesh_src, Mesh *mesh_dst, int actshape_uid)
+static KeyBlock *keyblock_ensure_from_uid(Key &key, const int uid, const StringRefNull name)
{
- KeyBlock *kb;
- int i, j, tot;
-
- if (!mesh_dst->key) {
- return;
+ if (KeyBlock *kb = BKE_keyblock_find_uid(&key, uid)) {
+ return kb;
}
+ KeyBlock *kb = BKE_keyblock_add(&key, name.c_str());
+ kb->uid = uid;
+ return kb;
+}
- tot = CustomData_number_of_layers(&mesh_src->vdata, CD_SHAPEKEY);
- for (i = 0; i < tot; i++) {
- CustomDataLayer *layer =
- &mesh_src->vdata.layers[CustomData_get_layer_index_n(&mesh_src->vdata, CD_SHAPEKEY, i)];
- float(*kbcos)[3];
-
- for (kb = (KeyBlock *)mesh_dst->key->block.first; kb; kb = kb->next) {
- if (kb->uid == layer->uid) {
- break;
- }
- }
+static int find_object_active_key_uid(const Key &key, const Object &object)
+{
+ const int active_kb_index = object.shapenr - 1;
+ const KeyBlock *kb = (const KeyBlock *)BLI_findlink(&key.block, active_kb_index);
+ if (!kb) {
+ CLOG_ERROR(&LOG, "Could not find object's active shapekey %d", active_kb_index);
+ return -1;
+ }
+ return kb->uid;
+}
- if (!kb) {
- kb = BKE_keyblock_add(mesh_dst->key, layer->name);
- kb->uid = layer->uid;
- }
+static void move_shapekey_layers_to_keyblocks(Mesh &mesh, Key &key_dst, const int actshape_uid)
+{
+ using namespace blender::bke;
+ for (const int i : IndexRange(CustomData_number_of_layers(&mesh.vdata, CD_SHAPEKEY))) {
+ const int layer_index = CustomData_get_layer_index_n(&mesh.vdata, CD_SHAPEKEY, i);
+ CustomDataLayer &layer = mesh.vdata.layers[layer_index];
- if (kb->data) {
- MEM_freeN(kb->data);
- }
+ KeyBlock *kb = keyblock_ensure_from_uid(key_dst, layer.uid, layer.name);
+ MEM_SAFE_FREE(kb->data);
- const float(*cos)[3] = (const float(*)[3])CustomData_get_layer_n(
- &mesh_src->vdata, CD_SHAPEKEY, i);
- kb->totelem = mesh_src->totvert;
+ kb->totelem = mesh.totvert;
- kb->data = kbcos = (float(*)[3])MEM_malloc_arrayN(kb->totelem, sizeof(float[3]), __func__);
if (kb->uid == actshape_uid) {
- const Span<MVert> verts = mesh_src->verts();
- for (j = 0; j < mesh_src->totvert; j++, kbcos++) {
- copy_v3_v3(*kbcos, verts[j].co);
- }
+ kb->data = MEM_malloc_arrayN(kb->totelem, sizeof(float3), __func__);
+ MutableSpan<float3> kb_coords(static_cast<float3 *>(kb->data), kb->totelem);
+ mesh.attributes().lookup<float3>("position").materialize(kb_coords);
}
else {
- for (j = 0; j < kb->totelem; j++, cos++, kbcos++) {
- copy_v3_v3(*kbcos, *cos);
- }
+ kb->data = layer.data;
+ layer.data = nullptr;
}
}
- for (kb = (KeyBlock *)mesh_dst->key->block.first; kb; kb = kb->next) {
- if (kb->totelem != mesh_src->totvert) {
- if (kb->data) {
- MEM_freeN(kb->data);
- }
-
- kb->totelem = mesh_src->totvert;
- kb->data = MEM_calloc_arrayN(kb->totelem, sizeof(float[3]), __func__);
- CLOG_ERROR(&LOG, "lost a shapekey layer: '%s'! (bmesh internal error)", kb->name);
+ LISTBASE_FOREACH (KeyBlock *, kb, &key_dst.block) {
+ if (kb->totelem != mesh.totvert) {
+ MEM_SAFE_FREE(kb->data);
}
+ kb->totelem = mesh.totvert;
+ kb->data = MEM_cnew_array<float3>(kb->totelem, __func__);
+ CLOG_ERROR(&LOG, "Data for shape key '%s' on mesh missing from evaluated mesh ", kb->name);
}
}
-void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
- Mesh *mesh_dst,
- Object *ob,
- const CustomData_MeshMasks *mask,
- bool take_ownership)
+void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob)
{
using namespace blender::bke;
BLI_assert(mesh_src->id.tag & LIB_TAG_NO_MAIN);
-
- /* mesh_src might depend on mesh_dst, so we need to do everything with a local copy */
- /* TODO(Sybren): the above claim came from 2.7x derived-mesh code (DM_to_mesh);
- * check whether it is still true with Mesh */
- Mesh tmp = blender::dna::shallow_copy(*mesh_dst);
- int totvert, totedge /*, totface */ /* UNUSED */, totloop, totpoly;
- bool did_shapekeys = false;
- eCDAllocType alloctype = CD_DUPLICATE;
-
- if (take_ownership /* && dm->type == DM_TYPE_CDDM && dm->needsFree */) {
- bool has_any_referenced_layers = CustomData_has_referenced(&mesh_src->vdata) ||
- CustomData_has_referenced(&mesh_src->edata) ||
- CustomData_has_referenced(&mesh_src->ldata) ||
- CustomData_has_referenced(&mesh_src->fdata) ||
- CustomData_has_referenced(&mesh_src->pdata);
- if (!has_any_referenced_layers) {
- alloctype = CD_ASSIGN;
- }
- }
- CustomData_reset(&tmp.vdata);
- CustomData_reset(&tmp.edata);
- CustomData_reset(&tmp.fdata);
- CustomData_reset(&tmp.ldata);
- CustomData_reset(&tmp.pdata);
-
- totvert = tmp.totvert = mesh_src->totvert;
- totedge = tmp.totedge = mesh_src->totedge;
- totloop = tmp.totloop = mesh_src->totloop;
- totpoly = tmp.totpoly = mesh_src->totpoly;
- tmp.totface = 0;
-
- CustomData_copy(&mesh_src->vdata, &tmp.vdata, mask->vmask, alloctype, totvert);
- CustomData_copy(&mesh_src->edata, &tmp.edata, mask->emask, alloctype, totedge);
- CustomData_copy(&mesh_src->ldata, &tmp.ldata, mask->lmask, alloctype, totloop);
- CustomData_copy(&mesh_src->pdata, &tmp.pdata, mask->pmask, alloctype, totpoly);
- tmp.cd_flag = mesh_src->cd_flag;
- tmp.runtime.deformed_only = mesh_src->runtime.deformed_only;
-
- /* Clear the normals completely, since the new vertex / polygon count might be different. */
- BKE_mesh_clear_derived_normals(&tmp);
-
- if (CustomData_has_layer(&mesh_src->vdata, CD_SHAPEKEY)) {
- KeyBlock *kb;
- int uid;
-
- if (ob) {
- kb = (KeyBlock *)BLI_findlink(&mesh_dst->key->block, ob->shapenr - 1);
- if (kb) {
- uid = kb->uid;
- }
- else {
- CLOG_ERROR(&LOG, "could not find active shapekey %d!", ob->shapenr - 1);
-
- uid = INT_MAX;
- }
- }
- else {
- /* if no object, set to INT_MAX so we don't mess up any shapekey layers */
- uid = INT_MAX;
- }
-
- shapekey_layers_to_keyblocks(mesh_src, mesh_dst, uid);
- did_shapekeys = true;
- }
-
- /* copy texture space */
if (ob) {
- BKE_mesh_texspace_copy_from_object(&tmp, ob);
+ BLI_assert(mesh_dst == ob->data);
}
- /* not all DerivedMeshes store their verts/edges/faces in CustomData, so
- * we set them here in case they are missing */
- /* TODO(Sybren): we could probably replace CD_ASSIGN with alloctype and
- * always directly pass mesh_src->mxxx, instead of using a ternary operator. */
- if (!CustomData_has_layer(&tmp.vdata, CD_MVERT)) {
- CustomData_add_layer(&tmp.vdata,
- CD_MVERT,
- CD_ASSIGN,
- (alloctype == CD_ASSIGN) ? mesh_src->verts_for_write().data() :
- MEM_dupallocN(mesh_src->verts().data()),
- totvert);
- }
- if (!CustomData_has_layer(&tmp.edata, CD_MEDGE)) {
- CustomData_add_layer(&tmp.edata,
- CD_MEDGE,
- CD_ASSIGN,
- (alloctype == CD_ASSIGN) ? mesh_src->edges_for_write().data() :
- MEM_dupallocN(mesh_src->edges().data()),
- totedge);
- }
- if (!CustomData_has_layer(&tmp.pdata, CD_MPOLY)) {
- CustomData_add_layer(&tmp.ldata,
- CD_MLOOP,
- CD_ASSIGN,
- (alloctype == CD_ASSIGN) ? mesh_src->loops_for_write().data() :
- MEM_dupallocN(mesh_src->loops().data()),
- tmp.totloop);
- CustomData_add_layer(&tmp.pdata,
- CD_MPOLY,
- CD_ASSIGN,
- (alloctype == CD_ASSIGN) ? mesh_src->polys_for_write().data() :
- MEM_dupallocN(mesh_src->polys().data()),
- tmp.totpoly);
- }
-
- /* object had got displacement layer, should copy this layer to save sculpted data */
- /* NOTE(nazgul): maybe some other layers should be copied? */
- if (CustomData_has_layer(&mesh_dst->ldata, CD_MDISPS)) {
- if (totloop == mesh_dst->totloop) {
- MDisps *mdisps = (MDisps *)CustomData_get_layer(&mesh_dst->ldata, CD_MDISPS);
- CustomData_add_layer(&tmp.ldata, CD_MDISPS, alloctype, mdisps, totloop);
- if (alloctype == CD_ASSIGN) {
- /* Assign nullptr to prevent double-free. */
- CustomData_set_layer(&mesh_dst->ldata, CD_MDISPS, nullptr);
- }
- }
- }
+ BKE_mesh_clear_geometry(mesh_dst);
- CustomData_free(&mesh_dst->vdata, mesh_dst->totvert);
- CustomData_free(&mesh_dst->edata, mesh_dst->totedge);
- CustomData_free(&mesh_dst->fdata, mesh_dst->totface);
- CustomData_free(&mesh_dst->ldata, mesh_dst->totloop);
- CustomData_free(&mesh_dst->pdata, mesh_dst->totpoly);
-
- /* ok, this should now use new CD shapekey data,
- * which should be fed through the modifier
- * stack */
- if (tmp.totvert != mesh_dst->totvert && !did_shapekeys && mesh_dst->key) {
- CLOG_ERROR(&LOG, "YEEK! this should be recoded! Shape key loss!: ID '%s'", tmp.id.name);
- if (tmp.key && !(tmp.id.tag & LIB_TAG_NO_MAIN)) {
- id_us_min(&tmp.key->id);
- }
- tmp.key = nullptr;
- }
-
- /* Clear selection history */
- MEM_SAFE_FREE(tmp.mselect);
- tmp.totselect = 0;
- tmp.texflag &= ~ME_AUTOSPACE_EVALUATED;
+ /* Make sure referenced layers have a single user so assigning them to the mesh in main doesn't
+ * share them. "Referenced" layers are not expected to be shared between original meshes. */
+ CustomData_duplicate_referenced_layers(&mesh_src->vdata, mesh_src->totvert);
+ CustomData_duplicate_referenced_layers(&mesh_src->edata, mesh_src->totedge);
+ CustomData_duplicate_referenced_layers(&mesh_src->pdata, mesh_src->totpoly);
+ CustomData_duplicate_referenced_layers(&mesh_src->ldata, mesh_src->totloop);
- /* Clear any run-time data.
- * Even though this mesh won't typically have run-time data, the Python API can for e.g.
- * create loop-triangle cache here, which is confusing when left in the mesh, see: T81136. */
- BKE_mesh_runtime_clear_geometry(&tmp);
+ mesh_dst->totvert = mesh_src->totvert;
+ mesh_dst->totedge = mesh_src->totedge;
+ mesh_dst->totpoly = mesh_src->totpoly;
+ mesh_dst->totloop = mesh_src->totloop;
- /* skip the listbase */
- MEMCPY_STRUCT_AFTER(mesh_dst, &tmp, id.prev);
+ /* Using #CD_MASK_MESH ensures that only data that should exist in Main meshes is moved. */
+ const CustomData_MeshMasks mask = CD_MASK_MESH;
+ CustomData_copy(&mesh_src->vdata, &mesh_dst->vdata, mask.vmask, CD_ASSIGN, mesh_src->totvert);
+ CustomData_copy(&mesh_src->edata, &mesh_dst->edata, mask.emask, CD_ASSIGN, mesh_src->totedge);
+ CustomData_copy(&mesh_src->pdata, &mesh_dst->pdata, mask.pmask, CD_ASSIGN, mesh_src->totpoly);
+ CustomData_copy(&mesh_src->ldata, &mesh_dst->ldata, mask.lmask, CD_ASSIGN, mesh_src->totloop);
BLI_freelistN(&mesh_dst->vertex_group_names);
- BKE_defgroup_copy_list(&mesh_dst->vertex_group_names, &mesh_src->vertex_group_names);
- mesh_dst->vertex_group_active_index = mesh_src->vertex_group_active_index;
-
- if (take_ownership) {
- if (alloctype == CD_ASSIGN) {
- CustomData_free_typemask(&mesh_src->vdata, mesh_src->totvert, ~mask->vmask);
- CustomData_free_typemask(&mesh_src->edata, mesh_src->totedge, ~mask->emask);
- CustomData_free_typemask(&mesh_src->ldata, mesh_src->totloop, ~mask->lmask);
- CustomData_free_typemask(&mesh_src->pdata, mesh_src->totpoly, ~mask->pmask);
+ mesh_dst->vertex_group_names = mesh_src->vertex_group_names;
+ BLI_listbase_clear(&mesh_src->vertex_group_names);
+
+ BKE_mesh_copy_parameters(mesh_dst, mesh_src);
+ mesh_dst->cd_flag = mesh_src->cd_flag;
+
+ /* For original meshes, shape key data is stored in the #Key data-block, so it
+ * must be moved from the storage in #CustomData layers used for evaluation. */
+ if (Key *key_dst = mesh_dst->key) {
+ if (CustomData_has_layer(&mesh_src->vdata, CD_SHAPEKEY)) {
+ /* If no object, set to -1 so we don't mess up any shapekey layers. */
+ const int uid_active = ob ? find_object_active_key_uid(*key_dst, *ob) : -1;
+ move_shapekey_layers_to_keyblocks(*mesh_src, *key_dst, uid_active);
+ }
+ else if (mesh_src->totvert != mesh_dst->totvert) {
+ CLOG_ERROR(&LOG, "Mesh in Main '%s' lost shape keys", mesh_src->id.name);
+ if (mesh_src->key) {
+ id_us_min(&mesh_src->key->id);
+ }
}
- BKE_id_free(nullptr, mesh_src);
}
- BKE_mesh_assert_normals_dirty_or_calculated(mesh_dst);
+ BKE_id_free(nullptr, mesh_src);
}
void BKE_mesh_nomain_to_meshkey(Mesh *mesh_src, Mesh *mesh_dst, KeyBlock *kb)
diff --git a/source/blender/blenkernel/intern/mesh_debug.cc b/source/blender/blenkernel/intern/mesh_debug.cc
index 1826a77d6f4..8a9ce901923 100644
--- a/source/blender/blenkernel/intern/mesh_debug.cc
+++ b/source/blender/blenkernel/intern/mesh_debug.cc
@@ -30,12 +30,6 @@
static void mesh_debug_info_from_cd_flag(const Mesh *me, DynStr *dynstr)
{
BLI_dynstr_append(dynstr, "'cd_flag': {");
- if (me->cd_flag & ME_CDFLAG_VERT_BWEIGHT) {
- BLI_dynstr_append(dynstr, "'VERT_BWEIGHT', ");
- }
- if (me->cd_flag & ME_CDFLAG_EDGE_BWEIGHT) {
- BLI_dynstr_append(dynstr, "'EDGE_BWEIGHT', ");
- }
if (me->cd_flag & ME_CDFLAG_EDGE_CREASE) {
BLI_dynstr_append(dynstr, "'EDGE_CREASE', ");
}
diff --git a/source/blender/blenkernel/intern/mesh_legacy_convert.cc b/source/blender/blenkernel/intern/mesh_legacy_convert.cc
index 2f67e303095..10fc8ff3195 100644
--- a/source/blender/blenkernel/intern/mesh_legacy_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_legacy_convert.cc
@@ -918,6 +918,67 @@ void BKE_mesh_add_mface_layers(CustomData *fdata, CustomData *ldata, int total)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Bevel Weight Conversion
+ * \{ */
+
+void BKE_mesh_legacy_bevel_weight_from_layers(Mesh *mesh)
+{
+ using namespace blender;
+ MutableSpan<MVert> verts = mesh->verts_for_write();
+ if (const float *weights = static_cast<const float *>(
+ CustomData_get_layer(&mesh->vdata, CD_BWEIGHT))) {
+ mesh->cd_flag |= ME_CDFLAG_VERT_BWEIGHT;
+ for (const int i : verts.index_range()) {
+ verts[i].bweight = std::clamp(weights[i], 0.0f, 1.0f) * 255.0f;
+ }
+ }
+ else {
+ mesh->cd_flag &= ~ME_CDFLAG_VERT_BWEIGHT;
+ for (const int i : verts.index_range()) {
+ verts[i].bweight = 0;
+ }
+ }
+ MutableSpan<MEdge> edges = mesh->edges_for_write();
+ if (const float *weights = static_cast<const float *>(
+ CustomData_get_layer(&mesh->edata, CD_BWEIGHT))) {
+ mesh->cd_flag |= ME_CDFLAG_EDGE_BWEIGHT;
+ for (const int i : edges.index_range()) {
+ edges[i].bweight = std::clamp(weights[i], 0.0f, 1.0f) * 255.0f;
+ }
+ }
+ else {
+ mesh->cd_flag &= ~ME_CDFLAG_EDGE_BWEIGHT;
+ for (const int i : edges.index_range()) {
+ edges[i].bweight = 0;
+ }
+ }
+}
+
+void BKE_mesh_legacy_bevel_weight_to_layers(Mesh *mesh)
+{
+ using namespace blender;
+ const Span<MVert> verts = mesh->verts();
+ if (mesh->cd_flag & ME_CDFLAG_VERT_BWEIGHT) {
+ float *weights = static_cast<float *>(
+ CustomData_add_layer(&mesh->vdata, CD_BWEIGHT, CD_CONSTRUCT, nullptr, verts.size()));
+ for (const int i : verts.index_range()) {
+ weights[i] = verts[i].bweight / 255.0f;
+ }
+ }
+
+ const Span<MEdge> edges = mesh->edges();
+ if (mesh->cd_flag & ME_CDFLAG_EDGE_BWEIGHT) {
+ float *weights = static_cast<float *>(
+ CustomData_add_layer(&mesh->edata, CD_BWEIGHT, CD_CONSTRUCT, nullptr, edges.size()));
+ for (const int i : edges.index_range()) {
+ weights[i] = edges[i].bweight / 255.0f;
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Hide Attribute and Legacy Flag Conversion
* \{ */
diff --git a/source/blender/blenkernel/intern/mesh_mirror.c b/source/blender/blenkernel/intern/mesh_mirror.c
index 2a64f6628f2..261bc3d150b 100644
--- a/source/blender/blenkernel/intern/mesh_mirror.c
+++ b/source/blender/blenkernel/intern/mesh_mirror.c
@@ -208,8 +208,8 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, maxLoops);
CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, maxPolys);
- /* Subsurf for eg won't have mesh data in the custom-data arrays.
- * now add mvert/medge/mpoly layers. */
+ /* Subdivision-surface for eg won't have mesh data in the custom-data arrays.
+ * Now add #MVert/#MEdge/#MPoly layers. */
if (!CustomData_has_layer(&mesh->vdata, CD_MVERT)) {
memcpy(BKE_mesh_verts_for_write(result), BKE_mesh_verts(mesh), sizeof(MVert) * mesh->totvert);
}
@@ -450,7 +450,7 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
MDeformVert *dvert = BKE_mesh_deform_verts_for_write(result) + maxVerts;
int *flip_map = NULL, flip_map_len = 0;
- flip_map = BKE_object_defgroup_flip_map(ob, &flip_map_len, false);
+ flip_map = BKE_object_defgroup_flip_map(ob, false, &flip_map_len);
if (flip_map) {
for (i = 0; i < maxVerts; dvert++, i++) {
diff --git a/source/blender/blenkernel/intern/mesh_tangent.cc b/source/blender/blenkernel/intern/mesh_tangent.cc
index 3c1cdf84b3d..8f9af5e9258 100644
--- a/source/blender/blenkernel/intern/mesh_tangent.cc
+++ b/source/blender/blenkernel/intern/mesh_tangent.cc
@@ -68,7 +68,7 @@ struct BKEMeshToTangent {
}
const MPoly *mpolys; /* faces */
- const MLoop *mloops; /* faces's vertices */
+ const MLoop *mloops; /* faces vertices */
const MVert *mverts; /* vertices */
const MLoopUV *luvs; /* texture coordinates */
const float (*lnors)[3]; /* loops' normals */
diff --git a/source/blender/blenkernel/intern/multires_unsubdivide.c b/source/blender/blenkernel/intern/multires_unsubdivide.c
index 9a0f7aa2126..353fbec6933 100644
--- a/source/blender/blenkernel/intern/multires_unsubdivide.c
+++ b/source/blender/blenkernel/intern/multires_unsubdivide.c
@@ -1252,7 +1252,7 @@ int multiresModifier_rebuild_subdiv(struct Depsgraph *depsgraph,
}
/* Copy the new base mesh to the original mesh. */
- BKE_mesh_nomain_to_mesh(unsubdiv_context.base_mesh, object->data, object, &CD_MASK_MESH, true);
+ BKE_mesh_nomain_to_mesh(unsubdiv_context.base_mesh, object->data, object);
Mesh *base_mesh = object->data;
multires_create_grids_in_unsubdivided_base_mesh(&unsubdiv_context, base_mesh);
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index fadcceae393..2ae0b456b0d 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -1931,6 +1931,9 @@ static void node_socket_free(bNodeSocket *sock, const bool do_id_user)
}
MEM_freeN(sock->default_value);
}
+ if (sock->default_attribute_name) {
+ MEM_freeN(sock->default_attribute_name);
+ }
MEM_delete(sock->runtime);
}
@@ -3015,6 +3018,9 @@ static void node_socket_interface_free(bNodeTree *UNUSED(ntree),
}
MEM_freeN(sock->default_value);
}
+ if (sock->default_attribute_name) {
+ MEM_freeN(sock->default_attribute_name);
+ }
MEM_delete(sock->runtime);
}
diff --git a/source/blender/blenkernel/intern/subdiv_mesh.cc b/source/blender/blenkernel/intern/subdiv_mesh.cc
index 5a2af36e83c..44bdd6e6d06 100644
--- a/source/blender/blenkernel/intern/subdiv_mesh.cc
+++ b/source/blender/blenkernel/intern/subdiv_mesh.cc
@@ -5,6 +5,8 @@
* \ingroup bke
*/
+#include <mutex>
+
#include "atomic_ops.h"
#include "DNA_key_types.h"
@@ -18,6 +20,7 @@
#include "BKE_customdata.h"
#include "BKE_key.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
#include "BKE_subdiv.h"
#include "BKE_subdiv_eval.h"
#include "BKE_subdiv_foreach.h"
@@ -25,6 +28,8 @@
#include "MEM_guardedalloc.h"
+using blender::Span;
+
/* -------------------------------------------------------------------- */
/** \name Subdivision Context
* \{ */
@@ -58,6 +63,11 @@ struct SubdivMeshContext {
/* Per-subdivided vertex counter of averaged values. */
int *accumulated_counters;
bool have_displacement;
+
+ /* Lazily initialize a map from vertices to connected edges. */
+ std::mutex vert_to_edge_map_mutex;
+ int *vert_to_edge_buffer;
+ MeshElemMap *vert_to_edge_map;
};
static void subdiv_mesh_ctx_cache_uv_layers(SubdivMeshContext *ctx)
@@ -106,6 +116,8 @@ static void subdiv_mesh_prepare_accumulator(SubdivMeshContext *ctx, int num_vert
static void subdiv_mesh_context_free(SubdivMeshContext *ctx)
{
MEM_SAFE_FREE(ctx->accumulated_counters);
+ MEM_SAFE_FREE(ctx->vert_to_edge_buffer);
+ MEM_SAFE_FREE(ctx->vert_to_edge_map);
}
/** \} */
@@ -779,7 +791,6 @@ static void subdiv_copy_edge_data(SubdivMeshContext *ctx,
const int subdiv_edge_index = subdiv_edge - ctx->subdiv_edges;
if (coarse_edge == nullptr) {
subdiv_edge->crease = 0;
- subdiv_edge->bweight = 0;
subdiv_edge->flag = 0;
if (!ctx->settings->use_optimal_display) {
subdiv_edge->flag |= ME_EDGERENDER;
@@ -961,25 +972,30 @@ static void subdiv_mesh_vertex_loose(const SubdivForeachContext *foreach_context
/* Get neighbor edges of the given one.
* - neighbors[0] is an edge adjacent to edge->v1.
* - neighbors[1] is an edge adjacent to edge->v2. */
-static void find_edge_neighbors(const Mesh *coarse_mesh,
- const MEdge *edge,
+static void find_edge_neighbors(const MEdge *coarse_edges,
+ const MeshElemMap *vert_to_edge_map,
+ const int edge_index,
const MEdge *neighbors[2])
{
- const blender::Span<MEdge> coarse_edges = coarse_mesh->edges();
+ const MEdge *edge = &coarse_edges[edge_index];
neighbors[0] = nullptr;
neighbors[1] = nullptr;
int neighbor_counters[2] = {0, 0};
- for (int edge_index = 0; edge_index < coarse_mesh->totedge; edge_index++) {
- const MEdge *current_edge = &coarse_edges[edge_index];
- if (current_edge == edge) {
+ for (const int i : Span(vert_to_edge_map[edge->v1].indices, vert_to_edge_map[edge->v1].count)) {
+ if (i == edge_index) {
continue;
}
- if (ELEM(edge->v1, current_edge->v1, current_edge->v2)) {
- neighbors[0] = current_edge;
+ if (ELEM(edge->v1, coarse_edges[i].v1, coarse_edges[i].v2)) {
+ neighbors[0] = &coarse_edges[i];
++neighbor_counters[0];
}
- if (ELEM(edge->v2, current_edge->v1, current_edge->v2)) {
- neighbors[1] = current_edge;
+ }
+ for (const int i : Span(vert_to_edge_map[edge->v2].indices, vert_to_edge_map[edge->v2].count)) {
+ if (i == edge_index) {
+ continue;
+ }
+ if (ELEM(edge->v2, coarse_edges[i].v1, coarse_edges[i].v2)) {
+ neighbors[1] = &coarse_edges[i];
++neighbor_counters[1];
}
}
@@ -994,12 +1010,11 @@ static void find_edge_neighbors(const Mesh *coarse_mesh,
}
}
-static void points_for_loose_edges_interpolation_get(const Mesh *coarse_mesh,
+static void points_for_loose_edges_interpolation_get(const MVert *coarse_mvert,
const MEdge *coarse_edge,
const MEdge *neighbors[2],
float points_r[4][3])
{
- const MVert *coarse_mvert = BKE_mesh_verts(coarse_mesh);
/* Middle points corresponds to the edge. */
copy_v3_v3(points_r[1], coarse_mvert[coarse_edge->v1].co);
copy_v3_v3(points_r[2], coarse_mvert[coarse_edge->v2].co);
@@ -1031,24 +1046,26 @@ static void points_for_loose_edges_interpolation_get(const Mesh *coarse_mesh,
}
}
-void BKE_subdiv_mesh_interpolate_position_on_edge(const Mesh *coarse_mesh,
- const MEdge *coarse_edge,
+void BKE_subdiv_mesh_interpolate_position_on_edge(const MVert *coarse_verts,
+ const MEdge *coarse_edges,
+ const MeshElemMap *vert_to_edge_map,
+ const int coarse_edge_index,
const bool is_simple,
const float u,
float pos_r[3])
{
+ const MEdge *coarse_edge = &coarse_edges[coarse_edge_index];
if (is_simple) {
- const MVert *coarse_mvert = BKE_mesh_verts(coarse_mesh);
- const MVert *vert_1 = &coarse_mvert[coarse_edge->v1];
- const MVert *vert_2 = &coarse_mvert[coarse_edge->v2];
+ const MVert *vert_1 = &coarse_verts[coarse_edge->v1];
+ const MVert *vert_2 = &coarse_verts[coarse_edge->v2];
interp_v3_v3v3(pos_r, vert_1->co, vert_2->co, u);
}
else {
/* Find neighbors of the coarse edge. */
const MEdge *neighbors[2];
- find_edge_neighbors(coarse_mesh, coarse_edge, neighbors);
+ find_edge_neighbors(coarse_edges, vert_to_edge_map, coarse_edge_index, neighbors);
float points[4][3];
- points_for_loose_edges_interpolation_get(coarse_mesh, coarse_edge, neighbors, points);
+ points_for_loose_edges_interpolation_get(coarse_verts, coarse_edge, neighbors, points);
float weights[4];
key_curve_position_weights(u, weights, KEY_BSPLINE);
interp_v3_v3v3v3v3(pos_r, points[0], points[1], points[2], points[3], weights);
@@ -1090,6 +1107,20 @@ static void subdiv_mesh_vertex_of_loose_edge(const SubdivForeachContext *foreach
const Mesh *coarse_mesh = ctx->coarse_mesh;
const MEdge *coarse_edge = &ctx->coarse_edges[coarse_edge_index];
const bool is_simple = ctx->subdiv->settings.is_simple;
+
+ /* Lazily initialize a vertex to edge map to avoid quadratic runtime when subdividing loose
+ * edges. Do this here to avoid the cost in common cases when there are no loose edges at all. */
+ if (ctx->vert_to_edge_map == NULL) {
+ std::lock_guard lock{ctx->vert_to_edge_map_mutex};
+ if (ctx->vert_to_edge_map == NULL) {
+ BKE_mesh_vert_edge_map_create(&ctx->vert_to_edge_map,
+ &ctx->vert_to_edge_buffer,
+ ctx->coarse_edges,
+ coarse_mesh->totvert,
+ ctx->coarse_mesh->totedge);
+ }
+ }
+
/* Interpolate custom data when not an end point.
* This data has already been copied from the original vertex by #subdiv_mesh_vertex_loose. */
if (!ELEM(u, 0.0, 1.0)) {
@@ -1097,13 +1128,15 @@ static void subdiv_mesh_vertex_of_loose_edge(const SubdivForeachContext *foreach
}
/* Interpolate coordinate. */
MVert *subdiv_vertex = &ctx->subdiv_verts[subdiv_vertex_index];
- BKE_subdiv_mesh_interpolate_position_on_edge(
- coarse_mesh, coarse_edge, is_simple, u, subdiv_vertex->co);
+ BKE_subdiv_mesh_interpolate_position_on_edge(ctx->coarse_verts,
+ ctx->coarse_edges,
+ ctx->vert_to_edge_map,
+ coarse_edge_index,
+ is_simple,
+ u,
+ subdiv_vertex->co);
/* Reset flags and such. */
subdiv_vertex->flag = 0;
- /* TODO(sergey): This matches old behavior, but we can as well interpolate
- * it. Maybe even using vertex varying attributes. */
- subdiv_vertex->bweight = 0.0f;
}
/** \} */
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index 88c260be9ba..0e5f9f30243 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -879,7 +879,7 @@ static void ccgDM_getFinalVertNo(DerivedMesh *dm, int vertNum, float r_no[3])
BLI_INLINE void ccgDM_to_MVert(MVert *mv, const CCGKey *key, CCGElem *elem)
{
copy_v3_v3(mv->co, CCG_elem_co(key, elem));
- mv->flag = mv->bweight = 0;
+ mv->flag = 0;
}
static void ccgDM_copyFinalVertArray(DerivedMesh *dm, MVert *mvert)
@@ -949,7 +949,7 @@ BLI_INLINE void ccgDM_to_MEdge(MEdge *med, const int v1, const int v2, const sho
{
med->v1 = v1;
med->v2 = v2;
- med->crease = med->bweight = 0;
+ med->crease = 0;
med->flag = flag;
}
diff --git a/source/blender/blenlib/BLI_bit_vector.hh b/source/blender/blenlib/BLI_bit_vector.hh
index 3cbd2483a31..2cec190f84a 100644
--- a/source/blender/blenlib/BLI_bit_vector.hh
+++ b/source/blender/blenlib/BLI_bit_vector.hh
@@ -196,7 +196,7 @@ class BitVector {
/** Current size of the vector in bits. */
int64_t size_in_bits_;
- /** Number of bits that fit into the vector until a reallocation has to occure. */
+ /** Number of bits that fit into the vector until a reallocation has to occur. */
int64_t capacity_in_bits_;
/** Used for allocations when the inline buffer is too small. */
diff --git a/source/blender/blenlib/BLI_float3x3.hh b/source/blender/blenlib/BLI_float3x3.hh
index 6a9e7dd04f0..178973c155d 100644
--- a/source/blender/blenlib/BLI_float3x3.hh
+++ b/source/blender/blenlib/BLI_float3x3.hh
@@ -63,6 +63,15 @@ struct float3x3 {
return result;
}
+ static float3x3 from_scale(const float2 scale)
+ {
+ float3x3 result = zero();
+ result.values[0][0] = scale.x;
+ result.values[1][1] = scale.y;
+ result.values[2][2] = 1.0f;
+ return result;
+ }
+
static float3x3 from_translation_rotation_scale(const float2 translation,
float rotation,
const float2 scale)
@@ -190,6 +199,13 @@ struct float3x3 {
return result;
}
+ float2 scale_2d() const
+ {
+ float2 scale;
+ mat3_to_size_2d(scale, values);
+ return scale;
+ }
+
friend bool operator==(const float3x3 &a, const float3x3 &b)
{
return equals_m3m3(a.values, b.values);
diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index 467e6db4805..19943614881 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -410,6 +410,8 @@ float mat4_to_xy_scale(const float mat[4][4]);
void size_to_mat3(float R[3][3], const float size[3]);
void size_to_mat4(float R[4][4], const float size[3]);
+/** Return 2D size assuming the given matrix is a 2D affine matrix. */
+void mat3_to_size_2d(float size[2], const float M[3][3]);
void mat3_to_size(float size[3], const float M[3][3]);
void mat4_to_size(float size[3], const float M[4][4]);
diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h
index 06dd9ab0db9..75002f52d94 100644
--- a/source/blender/blenlib/BLI_path_util.h
+++ b/source/blender/blenlib/BLI_path_util.h
@@ -36,16 +36,6 @@ void BLI_setenv_if_new(const char *env, const char *val) ATTR_NONNULL(1);
const char *BLI_getenv(const char *env) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
/**
- * Returns in `string` the concatenation of `dir` and `file` (also with `relabase` on the
- * front if specified and `dir` begins with "//"). Normalizes all occurrences of path
- * separators, including ensuring there is exactly one between the copies of `dir` and `file`,
- * and between the copies of `relabase` and `dir`.
- *
- * \param relabase: Optional prefix to substitute for "//" on front of `dir`.
- * \param string: Area to return result.
- */
-void BLI_make_file_string(const char *relabase, char *string, const char *dir, const char *file);
-/**
* Ensures that the parent directory of `name` exists.
*
* \return true on success (i.e. given path now exists on file-system), false otherwise.
diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c
index e96b12033a9..221ae84e74d 100644
--- a/source/blender/blenlib/intern/math_matrix.c
+++ b/source/blender/blenlib/intern/math_matrix.c
@@ -2127,6 +2127,12 @@ void size_to_mat4(float R[4][4], const float size[3])
R[3][3] = 1.0f;
}
+void mat3_to_size_2d(float size[2], const float M[3][3])
+{
+ size[0] = len_v2(M[0]);
+ size[1] = len_v2(M[1]);
+}
+
void mat3_to_size(float size[3], const float M[3][3])
{
size[0] = len_v3(M[0]);
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c
index 623dd572b11..1e95aa3b7b0 100644
--- a/source/blender/blenlib/intern/path_util.c
+++ b/source/blender/blenlib/intern/path_util.c
@@ -1204,87 +1204,6 @@ bool BLI_make_existing_file(const char *name)
return BLI_dir_create_recursive(di);
}
-void BLI_make_file_string(const char *relabase, char *string, const char *dir, const char *file)
-{
- int sl;
-
- if (string) {
- /* ensure this is always set even if dir/file are NULL */
- string[0] = '\0';
-
- if (ELEM(NULL, dir, file)) {
- return; /* We don't want any NULLs */
- }
- }
- else {
- return; /* string is NULL, probably shouldn't happen but return anyway */
- }
-
- /* Resolve relative references */
- if (relabase && dir[0] == '/' && dir[1] == '/') {
- char *lslash;
-
- /* Get the file name, chop everything past the last slash (ie. the filename) */
- strcpy(string, relabase);
-
- lslash = (char *)BLI_path_slash_rfind(string);
- if (lslash) {
- *(lslash + 1) = 0;
- }
-
- dir += 2; /* Skip over the relative reference */
- }
-#ifdef WIN32
- else {
- if (BLI_strnlen(dir, 3) >= 2 && dir[1] == ':') {
- BLI_strncpy(string, dir, 3);
- dir += 2;
- }
- else if (BLI_strnlen(dir, 3) >= 2 && BLI_path_is_unc(dir)) {
- string[0] = 0;
- }
- else { /* no drive specified */
- /* first option: get the drive from the relabase if it has one */
- if (relabase && BLI_strnlen(relabase, 3) >= 2 && relabase[1] == ':') {
- BLI_strncpy(string, relabase, 3);
- string[2] = '\\';
- string[3] = '\0';
- }
- else { /* we're out of luck here, guessing the first valid drive, usually c:\ */
- BLI_windows_get_default_root_dir(string);
- }
-
- /* ignore leading slashes */
- while (ELEM(*dir, '/', '\\')) {
- dir++;
- }
- }
- }
-#endif
-
- strcat(string, dir);
-
- /* Make sure string ends in one (and only one) slash */
- /* first trim all slashes from the end of the string */
- sl = strlen(string);
- while ((sl > 0) && ELEM(string[sl - 1], '/', '\\')) {
- string[sl - 1] = '\0';
- sl--;
- }
- /* since we've now removed all slashes, put back one slash at the end. */
- strcat(string, "/");
-
- while (ELEM(*file, '/', '\\')) {
- /* Trim slashes from the front of file */
- file++;
- }
-
- strcat(string, file);
-
- /* Push all slashes to the system preferred direction */
- BLI_path_slash_native(string);
-}
-
static bool path_extension_check_ex(const char *str,
const size_t str_len,
const char *ext,
diff --git a/source/blender/blenlib/tests/BLI_bit_vector_test.cc b/source/blender/blenlib/tests/BLI_bit_vector_test.cc
index c477b464f0c..210f2be012d 100644
--- a/source/blender/blenlib/tests/BLI_bit_vector_test.cc
+++ b/source/blender/blenlib/tests/BLI_bit_vector_test.cc
@@ -1,4 +1,4 @@
-/* Apache License, Version 2.0 */
+/* SPDX-License-Identifier: Apache-2.0 */
#include "BLI_bit_vector.hh"
#include "BLI_exception_safety_test_utils.hh"
diff --git a/source/blender/blenlib/tests/BLI_float3x3_test.cc b/source/blender/blenlib/tests/BLI_float3x3_test.cc
index d22993ee69e..cd823b6e368 100644
--- a/source/blender/blenlib/tests/BLI_float3x3_test.cc
+++ b/source/blender/blenlib/tests/BLI_float3x3_test.cc
@@ -34,6 +34,15 @@ TEST(float3x3, Rotation)
EXPECT_FLOAT_EQ(result[1], 1.0f);
}
+TEST(float3x3, Scale)
+{
+ float2 point(1.0f, 2.0f);
+ float3x3 transformation = float3x3::from_scale(float2(2.0f, 3.0f));
+ float2 result = transformation * point;
+ EXPECT_FLOAT_EQ(result[0], 2.0f);
+ EXPECT_FLOAT_EQ(result[1], 6.0f);
+}
+
TEST(float3x3, TranslationRotationScale)
{
float2 point(1.0f, 2.0f);
@@ -116,4 +125,11 @@ TEST(float3x3, Origin)
EXPECT_FLOAT_EQ(result[1], 3.0f);
}
+TEST(float3x3, GetScale2D)
+{
+ float2 scale(2.0f, 3.0f);
+ float3x3 transformation = float3x3::from_scale(scale);
+ EXPECT_EQ(scale, transformation.scale_2d());
+}
+
} // namespace blender::tests
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index c5cf80fe635..bf2017b80f4 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -3065,9 +3065,13 @@ static BHead *read_data_into_datamap(FileData *fd, BHead *bhead, const char *all
* With the code below we get the struct-name to help tracking down the leak.
* This is kept disabled as the #malloc for the text always leaks memory. */
#if 0
- {
- const short *sp = fd->filesdna->structs[bhead->SDNAnr];
- allocname = fd->filesdna->types[sp[0]];
+ if (bhead->SDNAnr == 0) {
+ /* The data type here is unclear because #writedata sets SDNAnr to 0. */
+ allocname = "likely raw data";
+ }
+ else {
+ SDNA_Struct *sp = fd->filesdna->structs[bhead->SDNAnr];
+ allocname = fd->filesdna->types[sp->type];
size_t allocname_size = strlen(allocname) + 1;
char *allocname_buf = malloc(allocname_size);
memcpy(allocname_buf, allocname, allocname_size);
diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.cc b/source/blender/bmesh/intern/bmesh_mesh_convert.cc
index ccd82865178..94440916603 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_convert.cc
+++ b/source/blender/bmesh/intern/bmesh_mesh_convert.cc
@@ -126,17 +126,6 @@ void BM_mesh_cd_flag_apply(BMesh *bm, const char cd_flag)
BLI_assert(bm->edata.totlayer == 0 || bm->edata.pool != nullptr);
BLI_assert(bm->pdata.totlayer == 0 || bm->pdata.pool != nullptr);
- if (cd_flag & ME_CDFLAG_VERT_BWEIGHT) {
- if (!CustomData_has_layer(&bm->vdata, CD_BWEIGHT)) {
- BM_data_layer_add(bm, &bm->vdata, CD_BWEIGHT);
- }
- }
- else {
- if (CustomData_has_layer(&bm->vdata, CD_BWEIGHT)) {
- BM_data_layer_free(bm, &bm->vdata, CD_BWEIGHT);
- }
- }
-
if (cd_flag & ME_CDFLAG_VERT_CREASE) {
if (!CustomData_has_layer(&bm->vdata, CD_CREASE)) {
BM_data_layer_add(bm, &bm->vdata, CD_CREASE);
@@ -148,17 +137,6 @@ void BM_mesh_cd_flag_apply(BMesh *bm, const char cd_flag)
}
}
- if (cd_flag & ME_CDFLAG_EDGE_BWEIGHT) {
- if (!CustomData_has_layer(&bm->edata, CD_BWEIGHT)) {
- BM_data_layer_add(bm, &bm->edata, CD_BWEIGHT);
- }
- }
- else {
- if (CustomData_has_layer(&bm->edata, CD_BWEIGHT)) {
- BM_data_layer_free(bm, &bm->edata, CD_BWEIGHT);
- }
- }
-
if (cd_flag & ME_CDFLAG_EDGE_CREASE) {
if (!CustomData_has_layer(&bm->edata, CD_CREASE)) {
BM_data_layer_add(bm, &bm->edata, CD_CREASE);
@@ -174,15 +152,9 @@ void BM_mesh_cd_flag_apply(BMesh *bm, const char cd_flag)
char BM_mesh_cd_flag_from_bmesh(BMesh *bm)
{
char cd_flag = 0;
- if (CustomData_has_layer(&bm->vdata, CD_BWEIGHT)) {
- cd_flag |= ME_CDFLAG_VERT_BWEIGHT;
- }
if (CustomData_has_layer(&bm->vdata, CD_CREASE)) {
cd_flag |= ME_CDFLAG_VERT_CREASE;
}
- if (CustomData_has_layer(&bm->edata, CD_BWEIGHT)) {
- cd_flag |= ME_CDFLAG_EDGE_BWEIGHT;
- }
if (CustomData_has_layer(&bm->edata, CD_CREASE)) {
cd_flag |= ME_CDFLAG_EDGE_CREASE;
}
@@ -342,12 +314,6 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
/* Only copy these values over if the source mesh is flagged to be using them.
* Even if `bm` has these layers, they may have been added from another mesh, when `!is_new`. */
- const int cd_vert_bweight_offset = (me->cd_flag & ME_CDFLAG_VERT_BWEIGHT) ?
- CustomData_get_offset(&bm->vdata, CD_BWEIGHT) :
- -1;
- const int cd_edge_bweight_offset = (me->cd_flag & ME_CDFLAG_EDGE_BWEIGHT) ?
- CustomData_get_offset(&bm->edata, CD_BWEIGHT) :
- -1;
const int cd_edge_crease_offset = (me->cd_flag & ME_CDFLAG_EDGE_CREASE) ?
CustomData_get_offset(&bm->edata, CD_CREASE) :
-1;
@@ -391,10 +357,6 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
/* Copy Custom Data */
CustomData_to_bmesh_block(&me->vdata, &bm->vdata, i, &v->head.data, true);
- if (cd_vert_bweight_offset != -1) {
- BM_ELEM_CD_SET_FLOAT(v, cd_vert_bweight_offset, (float)mvert[i].bweight / 255.0f);
- }
-
/* Set shape key original index. */
if (cd_shape_keyindex_offset != -1) {
BM_ELEM_CD_SET_INT(v, cd_shape_keyindex_offset, i);
@@ -433,9 +395,6 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
/* Copy Custom Data */
CustomData_to_bmesh_block(&me->edata, &bm->edata, i, &e->head.data, true);
- if (cd_edge_bweight_offset != -1) {
- BM_ELEM_CD_SET_FLOAT(e, cd_edge_bweight_offset, (float)medge[i].bweight / 255.0f);
- }
if (cd_edge_crease_offset != -1) {
BM_ELEM_CD_SET_FLOAT(e, cd_edge_crease_offset, (float)medge[i].crease / 255.0f);
}
@@ -990,8 +949,6 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
BMIter iter;
int i, j;
- const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
- const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
const int cd_shape_keyindex_offset = CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX);
@@ -1073,10 +1030,6 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
/* Copy over custom-data. */
CustomData_from_bmesh_block(&bm->vdata, &me->vdata, v->head.data, i);
- if (cd_vert_bweight_offset != -1) {
- mvert[i].bweight = BM_ELEM_CD_GET_FLOAT_AS_UCHAR(v, cd_vert_bweight_offset);
- }
-
i++;
BM_CHECK_ELEMENT(v);
@@ -1103,9 +1056,6 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
if (cd_edge_crease_offset != -1) {
medge[i].crease = BM_ELEM_CD_GET_FLOAT_AS_UCHAR(e, cd_edge_crease_offset);
}
- if (cd_edge_bweight_offset != -1) {
- medge[i].bweight = BM_ELEM_CD_GET_FLOAT_AS_UCHAR(e, cd_edge_bweight_offset);
- }
i++;
BM_CHECK_ELEMENT(e);
@@ -1312,8 +1262,6 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
MLoop *mloop = loops.data();
unsigned int i, j;
- const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
- const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
bool need_hide_vert = false;
@@ -1339,14 +1287,6 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
need_hide_vert = true;
}
- if (cd_vert_bweight_offset != -1) {
- mv->bweight = BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eve, cd_vert_bweight_offset);
- }
-
- if (cd_vert_bweight_offset != -1) {
- mv->bweight = BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eve, cd_vert_bweight_offset);
- }
-
CustomData_from_bmesh_block(&bm->vdata, &me->vdata, eve->head.data, i);
}
bm->elem_index_dirty &= ~BM_VERT;
@@ -1375,9 +1315,6 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
if (cd_edge_crease_offset != -1) {
med->crease = BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eed, cd_edge_crease_offset);
}
- if (cd_edge_bweight_offset != -1) {
- med->bweight = BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eed, cd_edge_bweight_offset);
- }
CustomData_from_bmesh_block(&bm->edata, &me->edata, eed->head.data, i);
}
diff --git a/source/blender/compositor/nodes/COM_ScaleNode.cc b/source/blender/compositor/nodes/COM_ScaleNode.cc
index 4813e49cd11..1d613a030d7 100644
--- a/source/blender/compositor/nodes/COM_ScaleNode.cc
+++ b/source/blender/compositor/nodes/COM_ScaleNode.cc
@@ -25,7 +25,7 @@ void ScaleNode::convert_to_operations(NodeConverter &converter,
NodeOutput *output_socket = this->get_output_socket(0);
switch (bnode->custom1) {
- case CMP_SCALE_RELATIVE: {
+ case CMP_NODE_SCALE_RELATIVE: {
ScaleRelativeOperation *operation = new ScaleRelativeOperation();
converter.add_operation(operation);
@@ -39,7 +39,7 @@ void ScaleNode::convert_to_operations(NodeConverter &converter,
break;
}
- case CMP_SCALE_SCENEPERCENT: {
+ case CMP_NODE_SCALE_RENDER_PERCENT: {
SetValueOperation *scale_factor_operation = new SetValueOperation();
scale_factor_operation->set_value(context.get_render_percentage_as_factor());
converter.add_operation(scale_factor_operation);
@@ -59,13 +59,14 @@ void ScaleNode::convert_to_operations(NodeConverter &converter,
break;
}
- case CMP_SCALE_RENDERPERCENT: {
+ case CMP_NODE_SCALE_RENDER_SIZE: {
const RenderData *rd = context.get_render_data();
const float render_size_factor = context.get_render_percentage_as_factor();
ScaleFixedSizeOperation *operation = new ScaleFixedSizeOperation();
/* framing options */
- operation->set_is_aspect((bnode->custom2 & CMP_SCALE_RENDERSIZE_FRAME_ASPECT) != 0);
- operation->set_is_crop((bnode->custom2 & CMP_SCALE_RENDERSIZE_FRAME_CROP) != 0);
+ operation->set_is_aspect(
+ ELEM(bnode->custom2, CMP_NODE_SCALE_RENDER_SIZE_FIT, CMP_NODE_SCALE_RENDER_SIZE_CROP));
+ operation->set_is_crop(bnode->custom2 == CMP_NODE_SCALE_RENDER_SIZE_CROP);
operation->set_offset(bnode->custom3, bnode->custom4);
operation->set_new_width(rd->xsch * render_size_factor);
operation->set_new_height(rd->ysch * render_size_factor);
@@ -79,7 +80,7 @@ void ScaleNode::convert_to_operations(NodeConverter &converter,
break;
}
- case CMP_SCALE_ABSOLUTE: {
+ case CMP_NODE_SCALE_ABSOLUTE: {
/* TODO: what is the use of this one.... perhaps some issues when the ui was updated... */
ScaleAbsoluteOperation *operation = new ScaleAbsoluteOperation();
converter.add_operation(operation);
diff --git a/source/blender/compositor/operations/COM_SMAAOperation.cc b/source/blender/compositor/operations/COM_SMAAOperation.cc
index 11e51e81ef0..261426b31e2 100644
--- a/source/blender/compositor/operations/COM_SMAAOperation.cc
+++ b/source/blender/compositor/operations/COM_SMAAOperation.cc
@@ -12,7 +12,7 @@ extern "C" {
namespace blender::compositor {
/*
- * An implementation of Enhanced Subpixel Morphological Antialiasing (SMAA)
+ * An implementation of Enhanced Sub-pixel Morphological Anti-aliasing (SMAA)
*
* The algorithm was proposed by:
* Jorge Jimenez, Jose I. Echevarria, Tiago Sousa, Diego Gutierrez
diff --git a/source/blender/compositor/realtime_compositor/intern/compile_state.cc b/source/blender/compositor/realtime_compositor/intern/compile_state.cc
index 97c1e47e86e..5fa2fc9d544 100644
--- a/source/blender/compositor/realtime_compositor/intern/compile_state.cc
+++ b/source/blender/compositor/realtime_compositor/intern/compile_state.cc
@@ -149,6 +149,11 @@ Domain CompileState::compute_shader_node_domain(DNode node)
continue;
}
+ /* An input that skips realization can't be a domain input. */
+ if (input_descriptor.skip_realization) {
+ continue;
+ }
+
/* Notice that the lower the domain priority value is, the higher the priority is, hence the
* less than comparison. */
if (input_descriptor.domain_priority < current_domain_priority) {
diff --git a/source/blender/compositor/realtime_compositor/intern/operation.cc b/source/blender/compositor/realtime_compositor/intern/operation.cc
index fb02807d729..832196cc5ef 100644
--- a/source/blender/compositor/realtime_compositor/intern/operation.cc
+++ b/source/blender/compositor/realtime_compositor/intern/operation.cc
@@ -66,6 +66,11 @@ Domain Operation::compute_domain()
continue;
}
+ /* An input that skips realization can't be a domain input. */
+ if (descriptor.skip_realization) {
+ continue;
+ }
+
/* Notice that the lower the domain priority value is, the higher the priority is, hence the
* less than comparison. */
if (descriptor.domain_priority < current_domain_priority) {
diff --git a/source/blender/compositor/realtime_compositor/intern/utilities.cc b/source/blender/compositor/realtime_compositor/intern/utilities.cc
index 2e1baec98a8..1a5823b8441 100644
--- a/source/blender/compositor/realtime_compositor/intern/utilities.cc
+++ b/source/blender/compositor/realtime_compositor/intern/utilities.cc
@@ -116,6 +116,7 @@ InputDescriptor input_descriptor_from_input_socket(const bNodeSocket *socket)
}
const SocketDeclarationPtr &socket_declaration = node_declaration->inputs()[socket->index()];
input_descriptor.domain_priority = socket_declaration->compositor_domain_priority();
+ input_descriptor.skip_realization = socket_declaration->compositor_skip_realization();
input_descriptor.expects_single_value = socket_declaration->compositor_expects_single_value();
return input_descriptor;
}
diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c
index 7f722ff1764..614ea0b0892 100644
--- a/source/blender/draw/engines/eevee/eevee_lightcache.c
+++ b/source/blender/draw/engines/eevee/eevee_lightcache.c
@@ -849,7 +849,7 @@ static void eevee_lightbake_delete_resources(EEVEE_LightBake *lbake)
DRW_opengl_context_enable();
}
- /* XXX Free the resources contained in the viewlayer data
+ /* XXX: Free the resources contained in the view-layer data
* to be able to free the context before deleting the depsgraph. */
if (lbake->sldata) {
EEVEE_view_layer_data_free(lbake->sldata);
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index 8d47d80987c..8c6d96254ae 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -1015,7 +1015,7 @@ typedef struct EEVEE_PrivateData {
struct GHash *material_hash;
float background_alpha; /* TODO: find a better place for this. */
bool disable_ligthprobes;
- /* Chosen lightcache: can come from Lookdev or the viewlayer. */
+ /** Chosen light-cache: can come from Lookdev or the view-layer. */
struct LightCache *light_cache;
/* For planar probes */
float planar_texel_size[2];
diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_data.c b/source/blender/draw/engines/gpencil/gpencil_draw_data.c
index 65ddb80ad55..e54ac99a888 100644
--- a/source/blender/draw/engines/gpencil/gpencil_draw_data.c
+++ b/source/blender/draw/engines/gpencil/gpencil_draw_data.c
@@ -460,7 +460,7 @@ GPENCIL_ViewLayerData *GPENCIL_view_layer_data_ensure(void)
GPENCIL_ViewLayerData **vldata = (GPENCIL_ViewLayerData **)DRW_view_layer_engine_data_ensure(
&draw_engine_gpencil_type, gpencil_view_layer_data_free);
- /* NOTE(&fclem): Putting this stuff in viewlayer means it is shared by all viewports.
+ /* NOTE(@fclem): Putting this stuff in view-layer means it is shared by all viewports.
* For now it is ok, but in the future, it could become a problem if we implement
* the caching system. */
if (*vldata == NULL) {
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c
index 4f520e61936..42c396a0d43 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.c
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.c
@@ -799,7 +799,7 @@ static void gpencil_draw_mask(GPENCIL_Data *vedata, GPENCIL_tObject *ob, GPENCIL
}
GPENCIL_tLayer *mask_layer = gpencil_layer_cache_get(ob, i);
- /* When filtering by viewlayer, the mask could be null and must be ignored. */
+ /* When filtering by view-layer, the mask could be null and must be ignored. */
if (mask_layer == NULL) {
continue;
}
diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
index 51fbc5a3027..ab935809f96 100644
--- a/source/blender/draw/intern/draw_cache_impl_subdivision.cc
+++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
@@ -10,6 +10,7 @@
#include "BKE_attribute.hh"
#include "BKE_editmesh.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_scene.h"
@@ -2155,7 +2156,17 @@ void DRW_subdivide_loose_geom(DRWSubdivCache *subdiv_cache, MeshBufferCache *cac
int subd_vert_offset = 0;
/* Subdivide each loose coarse edge. */
+ const Span<MVert> coarse_verts = coarse_mesh->verts();
const Span<MEdge> coarse_edges = coarse_mesh->edges();
+
+ int *vert_to_edge_buffer;
+ MeshElemMap *vert_to_edge_map;
+ BKE_mesh_vert_edge_map_create(&vert_to_edge_map,
+ &vert_to_edge_buffer,
+ coarse_edges.data(),
+ coarse_mesh->totvert,
+ coarse_edges.size());
+
for (int i = 0; i < coarse_loose_edge_len; i++) {
const int coarse_edge_index = cache->loose_geom.edges[i];
const MEdge *coarse_edge = &coarse_edges[cache->loose_geom.edges[i]];
@@ -2169,8 +2180,13 @@ void DRW_subdivide_loose_geom(DRWSubdivCache *subdiv_cache, MeshBufferCache *cac
DRWSubdivLooseVertex &subd_v1 = loose_subd_verts[subd_vert_offset];
subd_v1.coarse_vertex_index = (i == 0) ? coarse_edge->v1 : -1u;
const float u1 = i * inv_resolution_1;
- BKE_subdiv_mesh_interpolate_position_on_edge(
- coarse_mesh, coarse_edge, is_simple, u1, subd_v1.co);
+ BKE_subdiv_mesh_interpolate_position_on_edge(coarse_verts.data(),
+ coarse_edges.data(),
+ vert_to_edge_map,
+ coarse_edge_index,
+ is_simple,
+ u1,
+ subd_v1.co);
subd_edge.loose_subdiv_v1_index = subd_vert_offset++;
@@ -2178,15 +2194,22 @@ void DRW_subdivide_loose_geom(DRWSubdivCache *subdiv_cache, MeshBufferCache *cac
DRWSubdivLooseVertex &subd_v2 = loose_subd_verts[subd_vert_offset];
subd_v2.coarse_vertex_index = ((i + 1) == resolution - 1) ? coarse_edge->v2 : -1u;
const float u2 = (i + 1) * inv_resolution_1;
- BKE_subdiv_mesh_interpolate_position_on_edge(
- coarse_mesh, coarse_edge, is_simple, u2, subd_v2.co);
+ BKE_subdiv_mesh_interpolate_position_on_edge(coarse_verts.data(),
+ coarse_edges.data(),
+ vert_to_edge_map,
+ coarse_edge_index,
+ is_simple,
+ u2,
+ subd_v2.co);
subd_edge.loose_subdiv_v2_index = subd_vert_offset++;
}
}
+ MEM_freeN(vert_to_edge_buffer);
+ MEM_freeN(vert_to_edge_map);
+
/* Copy the remaining loose_verts. */
- const Span<MVert> coarse_verts = coarse_mesh->verts();
for (int i = 0; i < coarse_loose_vert_len; i++) {
const int coarse_vertex_index = cache->loose_geom.verts[i];
const MVert &coarse_vertex = coarse_verts[coarse_vertex_index];
diff --git a/source/blender/draw/intern/draw_command.hh b/source/blender/draw/intern/draw_command.hh
index b9117580d91..46a9199a267 100644
--- a/source/blender/draw/intern/draw_command.hh
+++ b/source/blender/draw/intern/draw_command.hh
@@ -531,4 +531,4 @@ class DrawMultiBuf {
/** \} */
-}; // namespace blender::draw::command \ No newline at end of file
+}; // namespace blender::draw::command
diff --git a/source/blender/draw/intern/draw_manager.hh b/source/blender/draw/intern/draw_manager.hh
index aff56b0307b..fbd3d28d3f4 100644
--- a/source/blender/draw/intern/draw_manager.hh
+++ b/source/blender/draw/intern/draw_manager.hh
@@ -98,7 +98,6 @@ class Manager {
/** Number of object attribute recorded. */
uint attribute_len_ = 0;
- Object *object = nullptr;
Object *object_active = nullptr;
public:
diff --git a/source/blender/draw/intern/draw_resource.hh b/source/blender/draw/intern/draw_resource.hh
index 22ee43592a9..2df38e32ed2 100644
--- a/source/blender/draw/intern/draw_resource.hh
+++ b/source/blender/draw/intern/draw_resource.hh
@@ -85,10 +85,11 @@ inline void ObjectInfos::sync(const blender::draw::ObjectRef ref, bool is_active
if (ref.dupli_object == nullptr) {
/* TODO(fclem): this is rather costly to do at draw time. Maybe we can
* put it in ob->runtime and make depsgraph ensure it is up to date. */
- random = BLI_hash_int_2d(BLI_hash_string(ref.object->id.name + 2), 0) * (1.0f / 0xFFFFFFFF);
+ random = BLI_hash_int_2d(BLI_hash_string(ref.object->id.name + 2), 0) *
+ (1.0f / (float)0xFFFFFFFF);
}
else {
- random = ref.dupli_object->random_id * (1.0f / 0xFFFFFFFF);
+ random = ref.dupli_object->random_id * (1.0f / (float)0xFFFFFFFF);
}
/* Default values. Set if needed. */
random = 0.0f;
diff --git a/source/blender/draw/intern/draw_view.cc b/source/blender/draw/intern/draw_view.cc
index 326e8629e52..cb0e1370c28 100644
--- a/source/blender/draw/intern/draw_view.cc
+++ b/source/blender/draw/intern/draw_view.cc
@@ -260,13 +260,15 @@ void View::update_view_vectors()
}
/**
- * If ortho : view_vecs[0] is the near-bottom-left corner of the frustum and
- * view_vecs[1] is the vector going from the near-bottom-left corner to
- * the far-top-right corner.
- * If Persp : view_vecs[0].xy and view_vecs[1].xy are respectively the bottom-left corner
- * when Z = 1, and top-left corner if Z = 1.
- * view_vecs[0].z the near clip distance and view_vecs[1].z is the (signed)
- * distance from the near plane to the far clip plane.
+ * - If orthographic:
+ * `view_vecs[0]` is the near-bottom-left corner of the frustum and
+ * `view_vecs[1]` is the vector going from the near-bottom-left corner to
+ * the far-top-right corner.
+ * - If perspective:
+ * `view_vecs[0].xy` and `view_vecs[1].xy` are respectively the bottom-left corner
+ * when `Z = 1`, and top-left corner if `Z = 1`.
+ * `view_vecs[0].z` the near clip distance and `view_vecs[1].z` is the (signed)
+ * distance from the near plane to the far clip plane.
*/
copy_v3_v3(data_.viewvecs[0], view_vecs[0]);
diff --git a/source/blender/draw/intern/shaders/draw_resource_finalize_comp.glsl b/source/blender/draw/intern/shaders/draw_resource_finalize_comp.glsl
index d834435e54e..511d4e49651 100644
--- a/source/blender/draw/intern/shaders/draw_resource_finalize_comp.glsl
+++ b/source/blender/draw/intern/shaders/draw_resource_finalize_comp.glsl
@@ -61,4 +61,4 @@ void main()
vec3 size_inv = safe_rcp(size);
infos_buf[resource_id].orco_add = -loc * size_inv;
infos_buf[resource_id].orco_mul = size_inv;
-} \ No newline at end of file
+}
diff --git a/source/blender/draw/intern/shaders/draw_visibility_comp.glsl b/source/blender/draw/intern/shaders/draw_visibility_comp.glsl
index 7ec58c8f919..86add2d1fe2 100644
--- a/source/blender/draw/intern/shaders/draw_visibility_comp.glsl
+++ b/source/blender/draw/intern/shaders/draw_visibility_comp.glsl
@@ -43,4 +43,4 @@ void main()
mask_visibility_bit();
}
}
-} \ No newline at end of file
+}
diff --git a/source/blender/editors/interface/interface_drag.cc b/source/blender/editors/interface/interface_drag.cc
index 0c7c3a238ec..4bf2dac4151 100644
--- a/source/blender/editors/interface/interface_drag.cc
+++ b/source/blender/editors/interface/interface_drag.cc
@@ -37,7 +37,7 @@ void UI_but_drag_set_asset(uiBut *but,
{
wmDragAsset *asset_drag = WM_drag_create_asset_data(asset, metadata, path, import_type);
- /* FIXME: This is temporary evil solution to get scene/viewlayer/etc in the copy callback of the
+ /* FIXME: This is temporary evil solution to get scene/view-layer/etc in the copy callback of the
* #wmDropBox.
* TODO: Handle link/append in operator called at the end of the drop process, and NOT in its
* copy callback.
diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c
index 6a080e78086..a4d41400bae 100644
--- a/source/blender/editors/mesh/editmesh_mask_extract.c
+++ b/source/blender/editors/mesh/editmesh_mask_extract.c
@@ -204,7 +204,7 @@ static int geometry_extract_apply(bContext *C,
local_view_bits = v3d->local_view_uuid;
}
Object *new_ob = ED_object_add_type(C, OB_MESH, NULL, ob->loc, ob->rot, false, local_view_bits);
- BKE_mesh_nomain_to_mesh(new_mesh, new_ob->data, new_ob, &CD_MASK_EVERYTHING, true);
+ BKE_mesh_nomain_to_mesh(new_mesh, new_ob->data, new_ob);
/* Remove the Face Sets as they need to be recreated when entering Sculpt Mode in the new object.
* TODO(pablodobarro): In the future we can try to preserve them from the original mesh. */
@@ -548,7 +548,7 @@ static int paint_mask_slice_exec(bContext *C, wmOperator *op)
/* Remove the mask from the new object so it can be sculpted directly after slicing. */
CustomData_free_layers(&new_ob_mesh->vdata, CD_PAINT_MASK, new_ob_mesh->totvert);
- BKE_mesh_nomain_to_mesh(new_ob_mesh, new_ob->data, new_ob, &CD_MASK_MESH, true);
+ BKE_mesh_nomain_to_mesh(new_ob_mesh, new_ob->data, new_ob);
BKE_mesh_copy_parameters_for_eval(new_ob->data, mesh);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, new_ob);
BKE_mesh_batch_cache_dirty_tag(new_ob->data, BKE_MESH_BATCH_DIRTY_ALL);
@@ -557,7 +557,7 @@ static int paint_mask_slice_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_GEOM | ND_DATA, new_ob->data);
}
- BKE_mesh_nomain_to_mesh(new_mesh, ob->data, ob, &CD_MASK_MESH, true);
+ BKE_mesh_nomain_to_mesh(new_mesh, ob->data, ob);
if (ob->mode == OB_MODE_SCULPT) {
SculptSession *ss = ob->sculpt;
diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c
index 70f550a661e..ad51651faaa 100644
--- a/source/blender/editors/mesh/editmesh_path.c
+++ b/source/blender/editors/mesh/editmesh_path.c
@@ -21,6 +21,7 @@
#include "BLI_math.h"
#include "BKE_context.h"
+#include "BKE_customdata.h"
#include "BKE_editmesh.h"
#include "BKE_layer.h"
#include "BKE_report.h"
@@ -348,7 +349,9 @@ static void edgetag_ensure_cd_flag(Mesh *me, const char edge_mode)
BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_CREASE);
break;
case EDGE_MODE_TAG_BEVEL:
- BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_BWEIGHT);
+ if (!CustomData_has_layer(&bm->edata, CD_BWEIGHT)) {
+ BM_data_layer_add(bm, &bm->edata, CD_BWEIGHT);
+ }
break;
#ifdef WITH_FREESTYLE
case EDGE_MODE_TAG_FREESTYLE:
diff --git a/source/blender/editors/mesh/mesh_data.cc b/source/blender/editors/mesh/mesh_data.cc
index 4ee518b5662..e362501d86c 100644
--- a/source/blender/editors/mesh/mesh_data.cc
+++ b/source/blender/editors/mesh/mesh_data.cc
@@ -626,6 +626,28 @@ static int mesh_customdata_clear_exec__internal(bContext *C, char htype, int typ
return OPERATOR_CANCELLED;
}
+static int mesh_customdata_add_exec__internal(bContext *C, char htype, int type)
+{
+ Mesh *mesh = ED_mesh_context(C);
+
+ int tot;
+ CustomData *data = mesh_customdata_get_type(mesh, htype, &tot);
+
+ BLI_assert(CustomData_layertype_is_singleton(type) == true);
+
+ if (mesh->edit_mesh) {
+ BM_data_layer_add(mesh->edit_mesh->bm, data, type);
+ }
+ else {
+ CustomData_add_layer(data, type, CD_SET_DEFAULT, NULL, tot);
+ }
+
+ DEG_id_tag_update(&mesh->id, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, mesh);
+
+ return CustomData_has_layer(data, type) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+}
+
/* Clear Mask */
static bool mesh_customdata_mask_clear_poll(bContext *C)
{
@@ -848,6 +870,126 @@ void MESH_OT_customdata_custom_splitnormals_clear(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/* Vertex bevel weight. */
+
+static int mesh_customdata_bevel_weight_vertex_state(bContext *C)
+{
+ const Object *object = ED_object_context(C);
+
+ if (object && object->type == OB_MESH) {
+ const Mesh *mesh = static_cast<Mesh *>(object->data);
+ if (!ID_IS_LINKED(mesh)) {
+ const CustomData *data = GET_CD_DATA(mesh, vdata);
+ return CustomData_has_layer(data, CD_BWEIGHT);
+ }
+ }
+ return -1;
+}
+
+static bool mesh_customdata_bevel_weight_vertex_add_poll(bContext *C)
+{
+ return mesh_customdata_bevel_weight_vertex_state(C) == 0;
+}
+
+static int mesh_customdata_bevel_weight_vertex_add_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ return mesh_customdata_add_exec__internal(C, BM_VERT, CD_BWEIGHT);
+}
+
+void MESH_OT_customdata_bevel_weight_vertex_add(wmOperatorType *ot)
+{
+ ot->name = "Add Vertex Bevel Weight";
+ ot->idname = "MESH_OT_customdata_bevel_weight_vertex_add";
+ ot->description = "Add a vertex bevel weight layer";
+
+ ot->exec = mesh_customdata_bevel_weight_vertex_add_exec;
+ ot->poll = mesh_customdata_bevel_weight_vertex_add_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static bool mesh_customdata_bevel_weight_vertex_clear_poll(bContext *C)
+{
+ return (mesh_customdata_bevel_weight_vertex_state(C) == 1);
+}
+
+static int mesh_customdata_bevel_weight_vertex_clear_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ return mesh_customdata_clear_exec__internal(C, BM_VERT, CD_BWEIGHT);
+}
+
+void MESH_OT_customdata_bevel_weight_vertex_clear(wmOperatorType *ot)
+{
+ ot->name = "Clear Vertex Bevel Weight";
+ ot->idname = "MESH_OT_customdata_bevel_weight_vertex_clear";
+ ot->description = "Clear the vertex bevel weight layer";
+
+ ot->exec = mesh_customdata_bevel_weight_vertex_clear_exec;
+ ot->poll = mesh_customdata_bevel_weight_vertex_clear_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* Edge bevel weight. */
+
+static int mesh_customdata_bevel_weight_edge_state(bContext *C)
+{
+ const Object *ob = ED_object_context(C);
+
+ if (ob && ob->type == OB_MESH) {
+ const Mesh *mesh = static_cast<Mesh *>(ob->data);
+ if (!ID_IS_LINKED(mesh)) {
+ const CustomData *data = GET_CD_DATA(mesh, edata);
+ return CustomData_has_layer(data, CD_BWEIGHT);
+ }
+ }
+ return -1;
+}
+
+static bool mesh_customdata_bevel_weight_edge_add_poll(bContext *C)
+{
+ return mesh_customdata_bevel_weight_edge_state(C) == 0;
+}
+
+static int mesh_customdata_bevel_weight_edge_add_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ return mesh_customdata_add_exec__internal(C, BM_EDGE, CD_BWEIGHT);
+}
+
+void MESH_OT_customdata_bevel_weight_edge_add(wmOperatorType *ot)
+{
+ ot->name = "Add Edge Bevel Weight";
+ ot->idname = "MESH_OT_customdata_bevel_weight_edge_add";
+ ot->description = "Add an edge bevel weight layer";
+
+ ot->exec = mesh_customdata_bevel_weight_edge_add_exec;
+ ot->poll = mesh_customdata_bevel_weight_edge_add_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static bool mesh_customdata_bevel_weight_edge_clear_poll(bContext *C)
+{
+ return mesh_customdata_bevel_weight_edge_state(C) == 1;
+}
+
+static int mesh_customdata_bevel_weight_edge_clear_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ return mesh_customdata_clear_exec__internal(C, BM_EDGE, CD_BWEIGHT);
+}
+
+void MESH_OT_customdata_bevel_weight_edge_clear(wmOperatorType *ot)
+{
+ ot->name = "Clear Edge Bevel Weight";
+ ot->idname = "MESH_OT_customdata_bevel_weight_edge_clear";
+ ot->description = "Clear the edge bevel weight layer";
+
+ ot->exec = mesh_customdata_bevel_weight_edge_clear_exec;
+ ot->poll = mesh_customdata_bevel_weight_edge_clear_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/************************** Add Geometry Layers *************************/
void ED_mesh_update(Mesh *mesh, bContext *C, bool calc_edges, bool calc_edges_loose)
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index 4cf6f3d0eaa..75f63ed5d6f 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -315,6 +315,10 @@ void MESH_OT_customdata_skin_add(struct wmOperatorType *ot);
void MESH_OT_customdata_skin_clear(struct wmOperatorType *ot);
void MESH_OT_customdata_custom_splitnormals_add(struct wmOperatorType *ot);
void MESH_OT_customdata_custom_splitnormals_clear(struct wmOperatorType *ot);
+void MESH_OT_customdata_bevel_weight_vertex_add(struct wmOperatorType *ot);
+void MESH_OT_customdata_bevel_weight_vertex_clear(struct wmOperatorType *ot);
+void MESH_OT_customdata_bevel_weight_edge_add(struct wmOperatorType *ot);
+void MESH_OT_customdata_bevel_weight_edge_clear(struct wmOperatorType *ot);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c
index b9e78740e3c..01c92a59fc9 100644
--- a/source/blender/editors/mesh/mesh_ops.c
+++ b/source/blender/editors/mesh/mesh_ops.c
@@ -139,6 +139,10 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_customdata_skin_clear);
WM_operatortype_append(MESH_OT_customdata_custom_splitnormals_add);
WM_operatortype_append(MESH_OT_customdata_custom_splitnormals_clear);
+ WM_operatortype_append(MESH_OT_customdata_bevel_weight_vertex_add);
+ WM_operatortype_append(MESH_OT_customdata_bevel_weight_vertex_clear);
+ WM_operatortype_append(MESH_OT_customdata_bevel_weight_edge_add);
+ WM_operatortype_append(MESH_OT_customdata_bevel_weight_edge_clear);
WM_operatortype_append(MESH_OT_edgering_select);
WM_operatortype_append(MESH_OT_loopcut);
diff --git a/source/blender/editors/mesh/meshtools.cc b/source/blender/editors/mesh/meshtools.cc
index 9d1ea499e42..108fa210075 100644
--- a/source/blender/editors/mesh/meshtools.cc
+++ b/source/blender/editors/mesh/meshtools.cc
@@ -253,7 +253,7 @@ static void join_mesh_single(Depsgraph *depsgraph,
CustomData_merge(&me->pdata, pdata, CD_MASK_MESH.pmask, CD_SET_DEFAULT, totpoly);
CustomData_copy_data_named(&me->pdata, pdata, 0, *polyofs, me->totpoly);
- /* Apply matmap. In case we dont have material indices yet, create them if more than one
+ /* Apply matmap. In case we don't have material indices yet, create them if more than one
* material is the result of joining. */
int *material_indices = static_cast<int *>(
CustomData_get_layer_named(pdata, CD_PROP_INT32, "material_index"));
diff --git a/source/blender/editors/object/object_add.cc b/source/blender/editors/object/object_add.cc
index 272e6bbc70d..ee2bb551c40 100644
--- a/source/blender/editors/object/object_add.cc
+++ b/source/blender/editors/object/object_add.cc
@@ -3151,7 +3151,7 @@ static int object_convert_exec(bContext *C, wmOperator *op)
BKE_mesh_edges_set_draw_render(me_eval);
BKE_object_material_from_eval_data(bmain, newob, &me_eval->id);
Mesh *new_mesh = (Mesh *)newob->data;
- BKE_mesh_nomain_to_mesh(me_eval, new_mesh, newob, &CD_MASK_MESH, true);
+ BKE_mesh_nomain_to_mesh(me_eval, new_mesh, newob);
if (do_merge_customdata) {
BKE_mesh_merge_customdata_for_apply_modifier(new_mesh);
diff --git a/source/blender/editors/object/object_modifier.cc b/source/blender/editors/object/object_modifier.cc
index 97f88ce433c..61caa56cf7c 100644
--- a/source/blender/editors/object/object_modifier.cc
+++ b/source/blender/editors/object/object_modifier.cc
@@ -764,7 +764,7 @@ static bool modifier_apply_obdata(
Main *bmain = DEG_get_bmain(depsgraph);
BKE_object_material_from_eval_data(bmain, ob, &mesh_applied->id);
- BKE_mesh_nomain_to_mesh(mesh_applied, me, ob, &CD_MASK_MESH, true);
+ BKE_mesh_nomain_to_mesh(mesh_applied, me, ob);
/* Anonymous attributes shouldn't be available on the applied geometry. */
me->attributes_for_write().remove_anonymous();
diff --git a/source/blender/editors/object/object_remesh.cc b/source/blender/editors/object/object_remesh.cc
index 09489c50e9d..a6b51048209 100644
--- a/source/blender/editors/object/object_remesh.cc
+++ b/source/blender/editors/object/object_remesh.cc
@@ -179,7 +179,7 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op)
BKE_remesh_reproject_vertex_paint(new_mesh, mesh);
}
- BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true);
+ BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob);
if (smooth_normals) {
BKE_mesh_smooth_flag_set(static_cast<Mesh *>(ob->data), true);
@@ -905,7 +905,7 @@ static void quadriflow_start_job(void *customdata, short *stop, short *do_update
BKE_mesh_remesh_reproject_paint_mask(new_mesh, mesh);
}
- BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true);
+ BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob);
if (qj->smooth_normals) {
BKE_mesh_smooth_flag_set(static_cast<Mesh *>(ob->data), true);
diff --git a/source/blender/editors/object/object_vgroup.cc b/source/blender/editors/object/object_vgroup.cc
index d2cb7ad4b43..1d1263494c7 100644
--- a/source/blender/editors/object/object_vgroup.cc
+++ b/source/blender/editors/object/object_vgroup.cc
@@ -277,7 +277,7 @@ void ED_vgroup_parray_mirror_sync(Object *ob,
}
int flip_map_len;
- const int *flip_map = BKE_object_defgroup_flip_map(ob, &flip_map_len, true);
+ const int *flip_map = BKE_object_defgroup_flip_map(ob, true, &flip_map_len);
for (int i_src = 0; i_src < dvert_tot; i_src++) {
if (dvert_array[i_src] != nullptr) {
@@ -506,7 +506,7 @@ static void mesh_defvert_mirror_update_internal(Object *ob,
if (def_nr == -1) {
/* All vgroups, add groups where needed. */
int flip_map_len;
- int *flip_map = BKE_object_defgroup_flip_map(ob, &flip_map_len, true);
+ int *flip_map = BKE_object_defgroup_flip_map_unlocked(ob, true, &flip_map_len);
BKE_defvert_sync_mapped(dvert_dst, dvert_src, flip_map, flip_map_len, true);
MEM_freeN(flip_map);
}
@@ -2392,8 +2392,8 @@ void ED_vgroup_mirror(Object *ob,
}
if (flip_vgroups) {
- flip_map = all_vgroups ? BKE_object_defgroup_flip_map(ob, &flip_map_len, false) :
- BKE_object_defgroup_flip_map_single(ob, &flip_map_len, false, def_nr);
+ flip_map = all_vgroups ? BKE_object_defgroup_flip_map(ob, false, &flip_map_len) :
+ BKE_object_defgroup_flip_map_single(ob, false, def_nr, &flip_map_len);
BLI_assert(flip_map != nullptr);
diff --git a/source/blender/editors/render/render_preview.cc b/source/blender/editors/render/render_preview.cc
index 4c4a4e052ba..c97d5f3cbc8 100644
--- a/source/blender/editors/render/render_preview.cc
+++ b/source/blender/editors/render/render_preview.cc
@@ -1305,41 +1305,33 @@ static void shader_preview_free(void *customdata)
static ImBuf *icon_preview_imbuf_from_brush(Brush *brush)
{
- static const int flags = IB_rect | IB_multilayer | IB_metadata;
+ if (!brush->icon_imbuf && (brush->flag & BRUSH_CUSTOM_ICON) && brush->icon_filepath[0]) {
+ const int flags = IB_rect | IB_multilayer | IB_metadata;
- char filepath[FILE_MAX];
- const char *folder;
+ /* First use the path directly to try and load the file. */
+ char filepath[FILE_MAX];
- if (!(brush->icon_imbuf)) {
- if (brush->flag & BRUSH_CUSTOM_ICON) {
+ BLI_strncpy(filepath, brush->icon_filepath, sizeof(brush->icon_filepath));
+ BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL(&brush->id));
- if (brush->icon_filepath[0]) {
- /* First use the path directly to try and load the file. */
+ /* Use default color-spaces for brushes. */
+ brush->icon_imbuf = IMB_loadiffname(filepath, flags, nullptr);
- BLI_strncpy(filepath, brush->icon_filepath, sizeof(brush->icon_filepath));
- BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL(&brush->id));
+ /* Otherwise lets try to find it in other directories. */
+ if (!(brush->icon_imbuf)) {
+ const char *brushicons_dir = BKE_appdir_folder_id(BLENDER_DATAFILES, "brushicons");
+ /* Expected to be found, but don't crash if it's not. */
+ if (brushicons_dir) {
+ BLI_join_dirfile(filepath, sizeof(filepath), brushicons_dir, brush->icon_filepath);
- /* Use default color-spaces for brushes. */
+ /* Use default color spaces. */
brush->icon_imbuf = IMB_loadiffname(filepath, flags, nullptr);
-
- /* otherwise lets try to find it in other directories */
- if (!(brush->icon_imbuf)) {
- folder = BKE_appdir_folder_id(BLENDER_DATAFILES, "brushicons");
-
- BLI_make_file_string(
- BKE_main_blendfile_path_from_global(), filepath, folder, brush->icon_filepath);
-
- if (filepath[0]) {
- /* Use default color spaces. */
- brush->icon_imbuf = IMB_loadiffname(filepath, flags, nullptr);
- }
- }
-
- if (brush->icon_imbuf) {
- BKE_icon_changed(BKE_icon_id_ensure(&brush->id));
- }
}
}
+
+ if (brush->icon_imbuf) {
+ BKE_icon_changed(BKE_icon_id_ensure(&brush->id));
+ }
}
if (!(brush->icon_imbuf)) {
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_density.cc b/source/blender/editors/sculpt_paint/curves_sculpt_density.cc
index c33ee5e0727..a37eb4bb560 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_density.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_density.cc
@@ -137,11 +137,10 @@ struct DensityAddOperationExecutor {
/* Find UV map. */
VArraySpan<float2> surface_uv_map;
if (curves_id_orig_->surface_uv_map != nullptr) {
- surface_uv_map = surface_orig_->attributes()
- .lookup<float2>(curves_id_orig_->surface_uv_map, ATTR_DOMAIN_CORNER);
- surface_uv_map_eval_ = surface_eval_->attributes()
- .lookup<float2>(curves_id_orig_->surface_uv_map,
- ATTR_DOMAIN_CORNER);
+ surface_uv_map = surface_orig_->attributes().lookup<float2>(curves_id_orig_->surface_uv_map,
+ ATTR_DOMAIN_CORNER);
+ surface_uv_map_eval_ = surface_eval_->attributes().lookup<float2>(
+ curves_id_orig_->surface_uv_map, ATTR_DOMAIN_CORNER);
}
if (surface_uv_map.is_empty()) {
report_missing_uv_map_on_original_surface(stroke_extension.reports);
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index 332a0830081..0ea45f83336 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -1315,8 +1315,7 @@ static void sculpt_gesture_apply_trim(SculptGestureContext *sgcontext)
}),
sculpt_mesh);
BM_mesh_free(bm);
- BKE_mesh_nomain_to_mesh(
- result, sgcontext->vc.obact->data, sgcontext->vc.obact, &CD_MASK_MESH, true);
+ BKE_mesh_nomain_to_mesh(result, sgcontext->vc.obact->data, sgcontext->vc.obact);
}
static void sculpt_gesture_trim_begin(bContext *C, SculptGestureContext *sgcontext)
diff --git a/source/blender/editors/space_node/link_drag_search.cc b/source/blender/editors/space_node/link_drag_search.cc
index 21d5d8d7d26..a4be0a65230 100644
--- a/source/blender/editors/space_node/link_drag_search.cc
+++ b/source/blender/editors/space_node/link_drag_search.cc
@@ -227,7 +227,7 @@ 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("TRANSFORM_OT_translate", true);
+ wmOperatorType *ot = WM_operatortype_find("NODE_OT_translate_attach", true);
BLI_assert(ot);
PointerRNA ptr;
WM_operator_properties_create_ptr(&ptr, ot);
diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc
index 40f5d20d06d..7dbaa8ccd6d 100644
--- a/source/blender/editors/space_node/node_relationships.cc
+++ b/source/blender/editors/space_node/node_relationships.cc
@@ -1727,35 +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 OPERATOR_CANCELLED;
- }
- 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;
- }
- }
-
- if (parent) {
+ 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) {
- nodeDetachNode(node);
+ /* 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;
+ }
+ }
+
+ 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 82aaa2c3cc6..1f1ce9c0c2b 100644
--- a/source/blender/editors/space_node/node_select.cc
+++ b/source/blender/editors/space_node/node_select.cc
@@ -14,7 +14,6 @@
#include "BLI_lasso_2d.h"
#include "BLI_listbase.h"
#include "BLI_rect.h"
-#include "BLI_set.hh"
#include "BLI_string.h"
#include "BLI_string_search.h"
#include "BLI_string_utf8.h"
@@ -645,29 +644,28 @@ static bool node_mouse_select(bContext *C,
}
}
- if (!(changed || found)) {
- return false;
- }
+ /* 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);
+ }
- 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);
}
- WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr);
-
- return true;
+ return changed || found;
}
static int node_select_exec(bContext *C, wmOperator *op)
diff --git a/source/blender/editors/space_outliner/outliner_draw.cc b/source/blender/editors/space_outliner/outliner_draw.cc
index d8c94d8ee6c..4259d3572be 100644
--- a/source/blender/editors/space_outliner/outliner_draw.cc
+++ b/source/blender/editors/space_outliner/outliner_draw.cc
@@ -285,7 +285,7 @@ static void outliner_object_set_flag_recursive_fn(bContext *C,
}
else {
Base *base_iter = BKE_view_layer_base_find(view_layer, ob_iter);
- /* Child can be in a collection excluded from viewlayer. */
+ /* Child can be in a collection excluded from view-layer. */
if (base_iter == nullptr) {
continue;
}
diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c
index 5a5747bdf84..fe7e3a797c9 100644
--- a/source/blender/editors/space_view3d/view3d_buttons.c
+++ b/source/blender/editors/space_view3d/view3d_buttons.c
@@ -995,7 +995,9 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
if (apply_vcos || median->bv_weight || median->v_crease || median->skin[0] ||
median->skin[1]) {
if (median->bv_weight) {
- BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_VERT_BWEIGHT);
+ if (!CustomData_has_layer(&bm->vdata, CD_BWEIGHT)) {
+ BM_data_layer_add(bm, &bm->vdata, CD_BWEIGHT);
+ }
cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
BLI_assert(cd_vert_bweight_offset != -1);
@@ -1061,7 +1063,9 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
if (median->be_weight || median->e_crease) {
if (median->be_weight) {
- BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_BWEIGHT);
+ if (!CustomData_has_layer(&bm->edata, CD_BWEIGHT)) {
+ BM_data_layer_add(bm, &bm->edata, CD_BWEIGHT);
+ }
cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
BLI_assert(cd_edge_bweight_offset != -1);
diff --git a/source/blender/editors/transform/transform_convert_mesh_edge.c b/source/blender/editors/transform/transform_convert_mesh_edge.c
index becf3c7ce5a..b1627e62f8c 100644
--- a/source/blender/editors/transform/transform_convert_mesh_edge.c
+++ b/source/blender/editors/transform/transform_convert_mesh_edge.c
@@ -67,7 +67,9 @@ static void createTransEdge(bContext *UNUSED(C), TransInfo *t)
/* create data we need */
if (t->mode == TFM_BWEIGHT) {
- BM_mesh_cd_flag_ensure(em->bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_EDGE_BWEIGHT);
+ if (!CustomData_has_layer(&em->bm->edata, CD_BWEIGHT)) {
+ BM_data_layer_add(em->bm, &em->bm->edata, CD_BWEIGHT);
+ }
cd_edge_float_offset = CustomData_get_offset(&em->bm->edata, CD_BWEIGHT);
}
else { /* if (t->mode == TFM_EDGE_CREASE) { */
diff --git a/source/blender/editors/transform/transform_convert_mesh_vert_cdata.c b/source/blender/editors/transform/transform_convert_mesh_vert_cdata.c
index f05688f3325..39705f87a0d 100644
--- a/source/blender/editors/transform/transform_convert_mesh_vert_cdata.c
+++ b/source/blender/editors/transform/transform_convert_mesh_vert_cdata.c
@@ -84,7 +84,9 @@ static void createTransMeshVertCData(bContext *UNUSED(C), TransInfo *t)
int cd_offset = -1;
if (t->mode == TFM_BWEIGHT) {
- BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_VERT_BWEIGHT);
+ if (!CustomData_has_layer(&bm->vdata, CD_BWEIGHT)) {
+ BM_data_layer_add(bm, &bm->vdata, CD_BWEIGHT);
+ }
cd_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
}
else {
diff --git a/source/blender/geometry/intern/mesh_merge_by_distance.cc b/source/blender/geometry/intern/mesh_merge_by_distance.cc
index 831241aa274..17318c277aa 100644
--- a/source/blender/geometry/intern/mesh_merge_by_distance.cc
+++ b/source/blender/geometry/intern/mesh_merge_by_distance.cc
@@ -1233,7 +1233,6 @@ static void customdata_weld(
float no[3] = {0.0f, 0.0f, 0.0f};
#endif
int crease = 0;
- int bweight = 0;
short flag = 0;
/* interpolates a layer at a time */
@@ -1267,7 +1266,6 @@ static void customdata_weld(
no[1] += mv_src_no[1];
no[2] += mv_src_no[2];
#endif
- bweight += mv_src->bweight;
flag |= mv_src->flag;
}
}
@@ -1275,7 +1273,6 @@ static void customdata_weld(
for (j = 0; j < count; j++) {
MEdge *me_src = &((MEdge *)src_data)[src_indices[j]];
crease += me_src->crease;
- bweight += me_src->bweight;
flag |= me_src->flag;
}
}
@@ -1312,8 +1309,6 @@ static void customdata_weld(
if (type == CD_MVERT) {
MVert *mv = &((MVert *)layer_dst->data)[dest_index];
mul_v3_fl(co, fac);
- bweight *= fac;
- CLAMP_MAX(bweight, 255);
copy_v3_v3(mv->co, co);
#ifdef USE_WELD_NORMALS
@@ -1325,17 +1320,13 @@ static void customdata_weld(
#endif
mv->flag = (char)flag;
- mv->bweight = (char)bweight;
}
else if (type == CD_MEDGE) {
MEdge *me = &((MEdge *)layer_dst->data)[dest_index];
crease *= fac;
- bweight *= fac;
CLAMP_MAX(crease, 255);
- CLAMP_MAX(bweight, 255);
me->crease = (char)crease;
- me->bweight = (char)bweight;
me->flag = flag;
}
else if (CustomData_layer_has_interp(dest, dest_i)) {
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 47d4feb7ec9..8b38c22ae28 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -326,6 +326,7 @@ set(GLSL_SRC
shaders/compositor/compositor_alpha_crop.glsl
shaders/compositor/compositor_bilateral_blur.glsl
+ shaders/compositor/compositor_blur.glsl
shaders/compositor/compositor_bokeh_image.glsl
shaders/compositor/compositor_box_mask.glsl
shaders/compositor/compositor_convert.glsl
@@ -345,8 +346,11 @@ set(GLSL_SRC
shaders/compositor/compositor_screen_lens_distortion.glsl
shaders/compositor/compositor_set_alpha.glsl
shaders/compositor/compositor_split_viewer.glsl
+ shaders/compositor/compositor_symmetric_blur.glsl
+ shaders/compositor/compositor_symmetric_separable_blur.glsl
shaders/compositor/library/gpu_shader_compositor_alpha_over.glsl
+ shaders/compositor/library/gpu_shader_compositor_blur_common.glsl
shaders/compositor/library/gpu_shader_compositor_bright_contrast.glsl
shaders/compositor/library/gpu_shader_compositor_channel_matte.glsl
shaders/compositor/library/gpu_shader_compositor_chroma_matte.glsl
@@ -601,6 +605,7 @@ set(SRC_SHADER_CREATE_INFOS
shaders/compositor/infos/compositor_alpha_crop_info.hh
shaders/compositor/infos/compositor_bilateral_blur_info.hh
+ shaders/compositor/infos/compositor_blur_info.hh
shaders/compositor/infos/compositor_bokeh_image_info.hh
shaders/compositor/infos/compositor_box_mask_info.hh
shaders/compositor/infos/compositor_convert_info.hh
@@ -620,6 +625,8 @@ set(SRC_SHADER_CREATE_INFOS
shaders/compositor/infos/compositor_screen_lens_distortion_info.hh
shaders/compositor/infos/compositor_set_alpha_info.hh
shaders/compositor/infos/compositor_split_viewer_info.hh
+ shaders/compositor/infos/compositor_symmetric_blur_info.hh
+ shaders/compositor/infos/compositor_symmetric_separable_blur_info.hh
)
set(SRC_SHADER_CREATE_INFOS_MTL
diff --git a/source/blender/gpu/metal/kernels/gpu_shader_fullscreen_blit_info.hh b/source/blender/gpu/metal/kernels/gpu_shader_fullscreen_blit_info.hh
index 6af67ad44d2..469e488c176 100644
--- a/source/blender/gpu/metal/kernels/gpu_shader_fullscreen_blit_info.hh
+++ b/source/blender/gpu/metal/kernels/gpu_shader_fullscreen_blit_info.hh
@@ -20,4 +20,4 @@ GPU_SHADER_CREATE_INFO(fullscreen_blit)
.sampler(0, ImageType::FLOAT_2D, "imageTexture", Frequency::PASS)
.vertex_source("gpu_shader_fullscreen_blit_vert.glsl")
.fragment_source("gpu_shader_fullscreen_blit_frag.glsl")
- .do_static_compilation(true); \ No newline at end of file
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/metal/mtl_index_buffer.hh b/source/blender/gpu/metal/mtl_index_buffer.hh
index fde26b16927..702aa7f27d6 100644
--- a/source/blender/gpu/metal/mtl_index_buffer.hh
+++ b/source/blender/gpu/metal/mtl_index_buffer.hh
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup gpu
diff --git a/source/blender/gpu/metal/mtl_index_buffer.mm b/source/blender/gpu/metal/mtl_index_buffer.mm
index 99795d7bbd9..2195ab7538d 100644
--- a/source/blender/gpu/metal/mtl_index_buffer.mm
+++ b/source/blender/gpu/metal/mtl_index_buffer.mm
@@ -1,7 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup gpu
*/
+
#include "mtl_index_buffer.hh"
#include "mtl_context.hh"
#include "mtl_debug.hh"
diff --git a/source/blender/gpu/metal/mtl_primitive.hh b/source/blender/gpu/metal/mtl_primitive.hh
index 5aa7a533b95..b32854a04bf 100644
--- a/source/blender/gpu/metal/mtl_primitive.hh
+++ b/source/blender/gpu/metal/mtl_primitive.hh
@@ -97,4 +97,4 @@ static inline bool mtl_vertex_count_fits_primitive_type(uint32_t vertex_count,
return false;
}
-} // namespace blender::gpu \ No newline at end of file
+} // namespace blender::gpu
diff --git a/source/blender/gpu/shaders/common/gpu_shader_common_curves.glsl b/source/blender/gpu/shaders/common/gpu_shader_common_curves.glsl
index db8e114ec7a..e68c173c055 100644
--- a/source/blender/gpu/shaders/common/gpu_shader_common_curves.glsl
+++ b/source/blender/gpu/shaders/common/gpu_shader_common_curves.glsl
@@ -26,9 +26,29 @@ vec3 extrapolate_if_needed(vec3 parameters, vec3 values, vec3 start_slopes, vec3
return values + parameters * slopes;
}
-/* Curve maps are stored in sampler objects that are evaluated in the [0, 1] range, so normalize
- * parameters accordingly. */
-#define NORMALIZE_PARAMETER(parameter, minimum, range) ((parameter - minimum) * range)
+/* Curve maps are stored in texture samplers that are evaluated in the [0, 1] range, so normalize
+ * the parameters accordingly. Additionally, ensure that the parameters evaluate the sampler at the
+ * center of the pixels, because samplers are evaluated using linear interpolation. */
+float normalize_parameter(float parameter, float minimum, float range_divider)
+{
+ float normalized_parameter = (parameter - minimum) * range_divider;
+
+ /* Curve maps have a fixed width of 257. We offset by the equivalent of half a pixel and scale
+ * down such that the normalized parameter 1.0 corresponds to the center of the last pixel. */
+ float sampler_offset = 0.5 / 257.0;
+ float sampler_scale = 1.0 - (1.0 / 257.0);
+ return normalized_parameter * sampler_scale + sampler_offset;
+}
+
+/* Same as normalize_parameter but vectorized. */
+vec3 normalize_parameters(vec3 parameters, vec3 minimums, vec3 range_dividers)
+{
+ vec3 normalized_parameters = (parameters - minimums) * range_dividers;
+
+ float sampler_offset = 0.5 / 257.0;
+ float sampler_scale = 1.0 - (1.0 / 257.0);
+ return normalized_parameters * sampler_scale + sampler_offset;
+}
void curves_combined_rgb(float factor,
vec4 color,
@@ -46,7 +66,7 @@ void curves_combined_rgb(float factor,
/* First, evaluate alpha curve map at all channels. The alpha curve is the Combined curve in the
* UI. */
- vec3 parameters = NORMALIZE_PARAMETER(balanced.rgb, range_minimums.aaa, range_dividers.aaa);
+ vec3 parameters = normalize_parameters(balanced.rgb, range_minimums.aaa, range_dividers.aaa);
result.r = texture(curve_map, vec2(parameters.x, layer)).a;
result.g = texture(curve_map, vec2(parameters.y, layer)).a;
result.b = texture(curve_map, vec2(parameters.z, layer)).a;
@@ -55,13 +75,14 @@ void curves_combined_rgb(float factor,
result.rgb = extrapolate_if_needed(parameters, result.rgb, start_slopes.aaa, end_slopes.aaa);
/* Then, evaluate each channel on its curve map. */
- parameters = NORMALIZE_PARAMETER(result.rgb, range_minimums.rgb, range_dividers.rgb);
+ parameters = normalize_parameters(result.rgb, range_minimums.rgb, range_dividers.rgb);
result.r = texture(curve_map, vec2(parameters.r, layer)).r;
result.g = texture(curve_map, vec2(parameters.g, layer)).g;
result.b = texture(curve_map, vec2(parameters.b, layer)).b;
/* Then, extrapolate again if needed. */
result.rgb = extrapolate_if_needed(parameters, result.rgb, start_slopes.rgb, end_slopes.rgb);
+
result.a = color.a;
result = mix(color, result, factor);
@@ -83,13 +104,14 @@ void curves_combined_only(float factor,
/* Evaluate alpha curve map at all channels. The alpha curve is the Combined curve in the
* UI. */
- vec3 parameters = NORMALIZE_PARAMETER(balanced.rgb, range_minimum, range_divider);
+ vec3 parameters = normalize_parameters(balanced.rgb, vec3(range_minimum), vec3(range_divider));
result.r = texture(curve_map, vec2(parameters.x, layer)).a;
result.g = texture(curve_map, vec2(parameters.y, layer)).a;
result.b = texture(curve_map, vec2(parameters.z, layer)).a;
/* Then, extrapolate if needed. */
result.rgb = extrapolate_if_needed(parameters, result.rgb, vec3(start_slope), vec3(end_slope));
+
result.a = color.a;
result = mix(color, result, factor);
@@ -147,8 +169,8 @@ void curves_film_like(float factor,
/* Evaluate alpha curve map at the maximum and minimum channels. The alpha curve is the Combined
* curve in the UI. */
- float min_parameter = NORMALIZE_PARAMETER(minimum, range_minimum, range_divider);
- float max_parameter = NORMALIZE_PARAMETER(maximum, range_minimum, range_divider);
+ float min_parameter = normalize_parameter(minimum, range_minimum, range_divider);
+ float max_parameter = normalize_parameter(maximum, range_minimum, range_divider);
float new_min = texture(curve_map, vec2(min_parameter, layer)).a;
float new_max = texture(curve_map, vec2(max_parameter, layer)).a;
@@ -165,6 +187,7 @@ void curves_film_like(float factor,
vec3 median_or_min = mix(vec3(new_median), vec3(new_min), channel_is_min);
bvec3 channel_is_max = equal(balanced.rgb, vec3(maximum));
result.rgb = mix(median_or_min, vec3(new_max), channel_is_max);
+
result.a = color.a;
result = mix(color, result, clamp(factor, 0.0, 1.0));
@@ -180,7 +203,7 @@ void curves_vector(vec3 vector,
out vec3 result)
{
/* Evaluate each component on its curve map. */
- vec3 parameters = NORMALIZE_PARAMETER(vector, range_minimums, range_dividers);
+ vec3 parameters = normalize_parameters(vector, range_minimums, range_dividers);
result.x = texture(curve_map, vec2(parameters.x, layer)).x;
result.y = texture(curve_map, vec2(parameters.y, layer)).y;
result.z = texture(curve_map, vec2(parameters.z, layer)).z;
@@ -214,7 +237,7 @@ void curves_float(float value,
out float result)
{
/* Evaluate the normalized value on the first curve map. */
- float parameter = NORMALIZE_PARAMETER(value, range_minimum, range_divider);
+ float parameter = normalize_parameter(value, range_minimum, range_divider);
result = texture(curve_map, vec2(parameter, layer)).x;
/* Then, extrapolate if needed. */
diff --git a/source/blender/gpu/shaders/compositor/compositor_blur.glsl b/source/blender/gpu/shaders/compositor/compositor_blur.glsl
new file mode 100644
index 00000000000..4f981c84f59
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/compositor_blur.glsl
@@ -0,0 +1,55 @@
+#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl)
+
+vec4 load_input(ivec2 texel)
+{
+ vec4 color;
+ if (extend_bounds) {
+ /* If bounds are extended, then we treat the input as padded by a radius amount of pixels. So
+ * we load the input with an offset by the radius amount and fallback to a transparent color if
+ * it is out of bounds. */
+ color = texture_load(input_tx, texel - radius, vec4(0.0));
+ }
+ else {
+ color = texture_load(input_tx, texel);
+ }
+
+ return color;
+}
+
+/* Given the texel in the range [-radius, radius] in both axis, load the appropriate weight from
+ * the weights texture, where the texel (0, 0) is considered the center of weights texture. */
+vec4 load_weight(ivec2 texel)
+{
+ /* Add the radius to transform the texel into the range [0, radius * 2], then divide by the upper
+ * bound plus one to transform the texel into the normalized range [0, 1] needed to sample the
+ * weights sampler. Finally, also add 0.5 to sample at the center of the pixels. */
+ return texture(weights_tx, (texel + vec2(radius + 0.5)) / (radius * 2 + 1));
+}
+
+void main()
+{
+ ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
+
+ /* The mask input is treated as a boolean. If it is zero, then no blurring happens for this
+ * pixel. Otherwise, the pixel is blurred normally and the mask value is irrelevant. */
+ float mask = texture_load(mask_tx, texel).x;
+ if (mask == 0.0) {
+ imageStore(output_img, texel, texture_load(input_tx, texel));
+ return;
+ }
+
+ /* Go over the window of the given radius and accumulate the colors multiplied by their
+ * respective weights as well as the weights themselves. */
+ vec4 accumulated_color = vec4(0.0);
+ vec4 accumulated_weight = vec4(0.0);
+ for (int y = -radius; y <= radius; y++) {
+ for (int x = -radius; x <= radius; x++) {
+ vec4 weight = load_weight(ivec2(x, y));
+ accumulated_color += load_input(texel + ivec2(x, y)) * weight;
+ accumulated_weight += weight;
+ }
+ }
+
+ imageStore(output_img, texel, safe_divide(accumulated_color, accumulated_weight));
+}
diff --git a/source/blender/gpu/shaders/compositor/compositor_symmetric_blur.glsl b/source/blender/gpu/shaders/compositor/compositor_symmetric_blur.glsl
new file mode 100644
index 00000000000..df08991a35c
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/compositor_symmetric_blur.glsl
@@ -0,0 +1,77 @@
+#pragma BLENDER_REQUIRE(gpu_shader_compositor_blur_common.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl)
+
+vec4 load_input(ivec2 texel)
+{
+ vec4 color;
+ if (extend_bounds) {
+ /* If bounds are extended, then we treat the input as padded by a radius amount of pixels. So
+ * we load the input with an offset by the radius amount and fallback to a transparent color if
+ * it is out of bounds. Notice that we subtract 1 because the weights texture have an extra
+ * center weight, see the SymmetricBlurWeights for more information. */
+ ivec2 blur_size = texture_size(weights_tx) - 1;
+ color = texture_load(input_tx, texel - blur_size, vec4(0.0));
+ }
+ else {
+ color = texture_load(input_tx, texel);
+ }
+
+ if (gamma_correct) {
+ color = gamma_correct_blur_input(color);
+ }
+
+ return color;
+}
+
+void main()
+{
+ ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
+
+ vec4 accumulated_color = vec4(0.0);
+
+ /* First, compute the contribution of the center pixel. */
+ vec4 center_color = load_input(texel);
+ accumulated_color += center_color * texture_load(weights_tx, ivec2(0)).x;
+
+ ivec2 weights_size = texture_size(weights_tx);
+
+ /* Then, compute the contributions of the pixels along the x axis of the filter, noting that the
+ * weights texture only stores the weights for the positive half, but since the filter is
+ * symmetric, the same weight is used for the negative half and we add both of their
+ * contributions. */
+ for (int x = 1; x < weights_size.x; x++) {
+ float weight = texture_load(weights_tx, ivec2(x, 0)).x;
+ accumulated_color += load_input(texel + ivec2(x, 0)) * weight;
+ accumulated_color += load_input(texel + ivec2(-x, 0)) * weight;
+ }
+
+ /* Then, compute the contributions of the pixels along the y axis of the filter, noting that the
+ * weights texture only stores the weights for the positive half, but since the filter is
+ * symmetric, the same weight is used for the negative half and we add both of their
+ * contributions. */
+ for (int y = 1; y < weights_size.y; y++) {
+ float weight = texture_load(weights_tx, ivec2(0, y)).x;
+ accumulated_color += load_input(texel + ivec2(0, y)) * weight;
+ accumulated_color += load_input(texel + ivec2(0, -y)) * weight;
+ }
+
+ /* Finally, compute the contributions of the pixels in the four quadrants of the filter, noting
+ * that the weights texture only stores the weights for the upper right quadrant, but since the
+ * filter is symmetric, the same weight is used for the rest of the quadrants and we add all four
+ * of their contributions. */
+ for (int y = 1; y < weights_size.y; y++) {
+ for (int x = 1; x < weights_size.x; x++) {
+ float weight = texture_load(weights_tx, ivec2(x, y)).x;
+ accumulated_color += load_input(texel + ivec2(x, y)) * weight;
+ accumulated_color += load_input(texel + ivec2(-x, y)) * weight;
+ accumulated_color += load_input(texel + ivec2(x, -y)) * weight;
+ accumulated_color += load_input(texel + ivec2(-x, -y)) * weight;
+ }
+ }
+
+ if (gamma_correct) {
+ accumulated_color = gamma_uncorrect_blur_output(accumulated_color);
+ }
+
+ imageStore(output_img, texel, accumulated_color);
+}
diff --git a/source/blender/gpu/shaders/compositor/compositor_symmetric_separable_blur.glsl b/source/blender/gpu/shaders/compositor/compositor_symmetric_separable_blur.glsl
new file mode 100644
index 00000000000..ab0c7baa787
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/compositor_symmetric_separable_blur.glsl
@@ -0,0 +1,53 @@
+#pragma BLENDER_REQUIRE(gpu_shader_compositor_blur_common.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl)
+
+vec4 load_input(ivec2 texel)
+{
+ vec4 color;
+ if (extend_bounds) {
+ /* If bounds are extended, then we treat the input as padded by a radius amount of pixels. So
+ * we load the input with an offset by the radius amount and fallback to a transparent color if
+ * it is out of bounds. Notice that we subtract 1 because the weights texture have an extra
+ * center weight, see the SymmetricSeparableBlurWeights for more information. */
+ int blur_size = texture_size(weights_tx) - 1;
+ color = texture_load(input_tx, texel - ivec2(blur_size, 0), vec4(0.0));
+ }
+ else {
+ color = texture_load(input_tx, texel);
+ }
+
+ if (gamma_correct_input) {
+ color = gamma_correct_blur_input(color);
+ }
+
+ return color;
+}
+
+void main()
+{
+ ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
+
+ vec4 accumulated_color = vec4(0.0);
+
+ /* First, compute the contribution of the center pixel. */
+ vec4 center_color = load_input(texel);
+ accumulated_color += center_color * texture_load(weights_tx, 0).x;
+
+ /* Then, compute the contributions of the pixel to the right and left, noting that the
+ * weights texture only stores the weights for the positive half, but since the filter is
+ * symmetric, the same weight is used for the negative half and we add both of their
+ * contributions. */
+ for (int i = 1; i < texture_size(weights_tx); i++) {
+ float weight = texture_load(weights_tx, i).x;
+ accumulated_color += load_input(texel + ivec2(i, 0)) * weight;
+ accumulated_color += load_input(texel + ivec2(-i, 0)) * weight;
+ }
+
+ if (gamma_uncorrect_output) {
+ accumulated_color = gamma_uncorrect_blur_output(accumulated_color);
+ }
+
+ /* Write the color using the transposed texel. See the execute_separable_blur_horizontal_pass
+ * method for more information on the rational behind this. */
+ imageStore(output_img, texel.yx, accumulated_color);
+}
diff --git a/source/blender/gpu/shaders/compositor/infos/compositor_blur_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_blur_info.hh
new file mode 100644
index 00000000000..36b772aa486
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/infos/compositor_blur_info.hh
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(compositor_blur)
+ .local_group_size(16, 16)
+ .push_constant(Type::INT, "radius")
+ .push_constant(Type::BOOL, "extend_bounds")
+ .sampler(0, ImageType::FLOAT_2D, "input_tx")
+ .sampler(1, ImageType::FLOAT_2D, "weights_tx")
+ .sampler(2, ImageType::FLOAT_2D, "mask_tx")
+ .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
+ .compute_source("compositor_blur.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/compositor/infos/compositor_symmetric_blur_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_symmetric_blur_info.hh
new file mode 100644
index 00000000000..8ba2b4e04ef
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/infos/compositor_symmetric_blur_info.hh
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(compositor_symmetric_blur)
+ .local_group_size(16, 16)
+ .push_constant(Type::BOOL, "extend_bounds")
+ .push_constant(Type::BOOL, "gamma_correct")
+ .sampler(0, ImageType::FLOAT_2D, "input_tx")
+ .sampler(1, ImageType::FLOAT_2D, "weights_tx")
+ .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
+ .compute_source("compositor_symmetric_blur.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/compositor/infos/compositor_symmetric_separable_blur_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_symmetric_separable_blur_info.hh
new file mode 100644
index 00000000000..57247dba4b8
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/infos/compositor_symmetric_separable_blur_info.hh
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(compositor_symmetric_separable_blur)
+ .local_group_size(16, 16)
+ .push_constant(Type::BOOL, "extend_bounds")
+ .push_constant(Type::BOOL, "gamma_correct_input")
+ .push_constant(Type::BOOL, "gamma_uncorrect_output")
+ .sampler(0, ImageType::FLOAT_2D, "input_tx")
+ .sampler(1, ImageType::FLOAT_1D, "weights_tx")
+ .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
+ .compute_source("compositor_symmetric_separable_blur.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_blur_common.glsl b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_blur_common.glsl
new file mode 100644
index 00000000000..e404c03bbb0
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_blur_common.glsl
@@ -0,0 +1,32 @@
+/* Preprocess the input of the blur filter by squaring it in its alpha straight form, assuming the
+ * given color is alpha premultiplied. */
+vec4 gamma_correct_blur_input(vec4 color)
+{
+ /* Unpremultiply alpha. */
+ color.rgb /= color.a > 0.0 ? color.a : 1.0;
+
+ /* Square color channel if it is positive, otherwise zero it. */
+ color.rgb *= mix(color.rgb, vec3(0.0), lessThan(color.rgb, vec3(0.0)));
+
+ /* Premultiply alpha to undo previous alpha unpremultiplication. */
+ color.rgb *= color.a > 0.0 ? color.a : 1.0;
+
+ return color;
+}
+
+/* Postprocess the output of the blur filter by taking its square root it in its alpha straight
+ * form, assuming the given color is alpha premultiplied. This essential undoes the processing done
+ * by the gamma_correct_blur_input function. */
+vec4 gamma_uncorrect_blur_output(vec4 color)
+{
+ /* Unpremultiply alpha. */
+ color.rgb /= color.a > 0.0 ? color.a : 1.0;
+
+ /* Take the square root of the color channel if it is positive, otherwise zero it. */
+ color.rgb = mix(sqrt(color.rgb), vec3(0.0), lessThan(color.rgb, vec3(0.0)));
+
+ /* Premultiply alpha to undo previous alpha unpremultiplication. */
+ color.rgb *= color.a > 0.0 ? color.a : 1.0;
+
+ return color;
+}
diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc
index 65d99e3f057..c07aaa37988 100644
--- a/source/blender/io/alembic/intern/abc_reader_mesh.cc
+++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc
@@ -135,8 +135,6 @@ static void read_mverts_interp(MVert *mverts,
interp_v3_v3v3(tmp, floor_pos.getValue(), ceil_pos.getValue(), static_cast<float>(weight));
copy_zup_from_yup(mvert.co, tmp);
-
- mvert.bweight = 0;
}
}
@@ -163,8 +161,6 @@ void read_mverts(Mesh &mesh, const P3fArraySamplePtr positions, const N3fArraySa
Imath::V3f pos_in = (*positions)[i];
copy_zup_from_yup(mvert.co, pos_in.getValue());
-
- mvert.bweight = 0;
}
if (normals) {
float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(&mesh);
@@ -619,11 +615,7 @@ void AbcMeshReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec
Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, "", 0.0f, nullptr);
if (read_mesh != mesh) {
- /* XXX FIXME: after 2.80; mesh->flag isn't copied by #BKE_mesh_nomain_to_mesh(). */
- /* read_mesh can be freed by BKE_mesh_nomain_to_mesh(), so get the flag before that happens. */
- uint16_t autosmooth = (read_mesh->flag & ME_AUTOSMOOTH);
- BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, &CD_MASK_EVERYTHING, true);
- mesh->flag |= autosmooth;
+ BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object);
}
if (m_settings->validate_meshes) {
@@ -1003,7 +995,7 @@ void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelec
Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, "", 0.0f, nullptr);
if (read_mesh != mesh) {
- BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, &CD_MASK_EVERYTHING, true);
+ BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object);
}
ISubDSchema::Sample sample;
diff --git a/source/blender/io/alembic/intern/abc_reader_points.cc b/source/blender/io/alembic/intern/abc_reader_points.cc
index ff189bc92dc..54ae71ad7a6 100644
--- a/source/blender/io/alembic/intern/abc_reader_points.cc
+++ b/source/blender/io/alembic/intern/abc_reader_points.cc
@@ -69,7 +69,7 @@ void AbcPointsReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSel
Mesh *read_mesh = this->read_mesh(mesh, sample_sel, 0, "", 0.0f, nullptr);
if (read_mesh != mesh) {
- BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, &CD_MASK_MESH, true);
+ BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object);
}
if (m_settings->validate_meshes) {
diff --git a/source/blender/io/collada/MeshImporter.cpp b/source/blender/io/collada/MeshImporter.cpp
index e7a4f7b6b51..b22346d0281 100644
--- a/source/blender/io/collada/MeshImporter.cpp
+++ b/source/blender/io/collada/MeshImporter.cpp
@@ -587,7 +587,6 @@ void MeshImporter::read_lines(COLLADAFW::Mesh *mesh, Mesh *me)
unsigned int *indices = mp->getPositionIndices().getData();
for (int j = 0; j < edge_count; j++, med++) {
- med->bweight = 0;
med->crease = 0;
med->flag |= ME_LOOSEEDGE;
med->v1 = indices[2 * j];
diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc
index 0b96cd8ce90..7cb4c65f166 100644
--- a/source/blender/io/usd/intern/usd_reader_mesh.cc
+++ b/source/blender/io/usd/intern/usd_reader_mesh.cc
@@ -248,11 +248,7 @@ void USDMeshReader::read_object_data(Main *bmain, const double motionSampleTime)
is_initial_load_ = false;
if (read_mesh != mesh) {
- /* FIXME: after 2.80; `mesh->flag` isn't copied by #BKE_mesh_nomain_to_mesh() */
- /* read_mesh can be freed by BKE_mesh_nomain_to_mesh(), so get the flag before that happens. */
- uint16_t autosmooth = (read_mesh->flag & ME_AUTOSMOOTH);
- BKE_mesh_nomain_to_mesh(read_mesh, mesh, object_, &CD_MASK_MESH, true);
- mesh->flag |= autosmooth;
+ BKE_mesh_nomain_to_mesh(read_mesh, mesh, object_);
}
readFaceSetsSample(bmain, mesh, motionSampleTime);
diff --git a/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc b/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc
index b1a2c7834f4..ef05534928a 100644
--- a/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc
+++ b/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc
@@ -69,11 +69,7 @@ Object *MeshFromGeometry::create_mesh(Main *bmain,
}
transform_object(obj, import_params);
- /* FIXME: after 2.80; `mesh->flag` isn't copied by #BKE_mesh_nomain_to_mesh() */
- const uint16_t autosmooth = (mesh->flag & ME_AUTOSMOOTH);
- Mesh *dst = static_cast<Mesh *>(obj->data);
- BKE_mesh_nomain_to_mesh(mesh, dst, obj, &CD_MASK_EVERYTHING, true);
- dst->flag |= autosmooth;
+ BKE_mesh_nomain_to_mesh(mesh, static_cast<Mesh *>(obj->data), obj);
/* NOTE: vertex groups have to be created after final mesh is assigned to the object. */
create_vertex_groups(obj);
diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h
index a83262d7639..6a2f25f3975 100644
--- a/source/blender/makesdna/DNA_gpencil_types.h
+++ b/source/blender/makesdna/DNA_gpencil_types.h
@@ -579,7 +579,7 @@ typedef enum eGPDlayer_Flag {
GP_LAYER_USE_MASK = (1 << 13), /* TODO: DEPRECATED */
/* Ruler Layer */
GP_LAYER_IS_RULER = (1 << 14),
- /* Disable masks in viewlayer render */
+ /* Disable masks in view-layer render */
GP_LAYER_DISABLE_MASKS_IN_VIEWLAYER = (1 << 15),
} eGPDlayer_Flag;
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index 00a9e36612c..d335b36950c 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -440,8 +440,10 @@ enum {
/** #Mesh.cd_flag */
enum {
+#ifdef DNA_DEPRECATED_ALLOW
ME_CDFLAG_VERT_BWEIGHT = 1 << 0,
ME_CDFLAG_EDGE_BWEIGHT = 1 << 1,
+#endif
ME_CDFLAG_EDGE_CREASE = 1 << 2,
ME_CDFLAG_VERT_CREASE = 1 << 3,
};
diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h
index e0333f3ef03..e621343b818 100644
--- a/source/blender/makesdna/DNA_meshdata_types.h
+++ b/source/blender/makesdna/DNA_meshdata_types.h
@@ -25,7 +25,11 @@ extern "C" {
*/
typedef struct MVert {
float co[3];
- char flag, bweight;
+ char flag;
+ /**
+ * Deprecated bevel weight storage, now located in #CD_BWEIGHT, except for file read and write.
+ */
+ char bweight DNA_DEPRECATED;
char _pad[2];
} MVert;
@@ -47,7 +51,11 @@ enum {
typedef struct MEdge {
/** Un-ordered vertex indices (cannot match). */
unsigned int v1, v2;
- char crease, bweight;
+ char crease;
+ /**
+ * Deprecated bevel weight storage, now located in #CD_BWEIGHT, except for file read and write.
+ */
+ char bweight DNA_DEPRECATED;
short flag;
} MEdge;
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 28bbd3a3e4e..b19210968d9 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -2029,6 +2029,21 @@ typedef enum CMPNodeFlipMode {
CMP_NODE_FLIP_X_Y = 2,
} CMPNodeFlipMode;
+/* Scale Node. Stored in custom1. */
+typedef enum CMPNodeScaleMethod {
+ CMP_NODE_SCALE_RELATIVE = 0,
+ CMP_NODE_SCALE_ABSOLUTE = 1,
+ CMP_NODE_SCALE_RENDER_PERCENT = 2,
+ CMP_NODE_SCALE_RENDER_SIZE = 3,
+} CMPNodeScaleMethod;
+
+/* Scale Node. Stored in custom2. */
+typedef enum CMPNodeScaleRenderSizeMethod {
+ CMP_NODE_SCALE_RENDER_SIZE_STRETCH = 0,
+ CMP_NODE_SCALE_RENDER_SIZE_FIT = 1,
+ CMP_NODE_SCALE_RENDER_SIZE_CROP = 2,
+} CMPNodeScaleRenderSizeMethod;
+
/* Filter Node. Stored in custom1. */
typedef enum CMPNodeFilterMethod {
CMP_NODE_FILTER_SOFT = 0,
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index c36e53a49cd..28ceb0d1d9d 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -108,13 +108,11 @@ static CustomData *rna_mesh_vdata(const PointerRNA *ptr)
Mesh *me = rna_mesh(ptr);
return rna_mesh_vdata_helper(me);
}
-# if 0
static CustomData *rna_mesh_edata(PointerRNA *ptr)
{
Mesh *me = rna_mesh(ptr);
return rna_mesh_edata_helper(me);
}
-# endif
static CustomData *rna_mesh_pdata(const PointerRNA *ptr)
{
Mesh *me = rna_mesh(ptr);
@@ -231,6 +229,16 @@ static bool rna_Mesh_has_custom_normals_get(PointerRNA *ptr)
return BKE_mesh_has_custom_loop_normals(me);
}
+static bool rna_Mesh_has_edge_bevel_weight_get(PointerRNA *ptr)
+{
+ return CustomData_has_layer(rna_mesh_edata(ptr), CD_BWEIGHT);
+}
+
+static bool rna_Mesh_has_vertex_bevel_weight_get(PointerRNA *ptr)
+{
+ return CustomData_has_layer(rna_mesh_vdata(ptr), CD_BWEIGHT);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -430,26 +438,36 @@ static void rna_MeshVertex_hide_set(PointerRNA *ptr, bool value)
static float rna_MeshVertex_bevel_weight_get(PointerRNA *ptr)
{
- MVert *mvert = (MVert *)ptr->data;
- return mvert->bweight / 255.0f;
+ const Mesh *mesh = rna_mesh(ptr);
+ const int index = rna_MeshVertex_index_get(ptr);
+ const float *values = (const float *)CustomData_get_layer(&mesh->vdata, CD_BWEIGHT);
+ return values == NULL ? 0.0f : values[index];
}
static void rna_MeshVertex_bevel_weight_set(PointerRNA *ptr, float value)
{
- MVert *mvert = (MVert *)ptr->data;
- mvert->bweight = round_fl_to_uchar_clamp(value * 255.0f);
+ Mesh *mesh = rna_mesh(ptr);
+ const int index = rna_MeshVertex_index_get(ptr);
+ float *values = (float *)CustomData_add_layer(
+ &mesh->vdata, CD_BWEIGHT, CD_SET_DEFAULT, NULL, mesh->totvert);
+ values[index] = clamp_f(value, 0.0f, 1.0f);
}
static float rna_MEdge_bevel_weight_get(PointerRNA *ptr)
{
- MEdge *medge = (MEdge *)ptr->data;
- return medge->bweight / 255.0f;
+ const Mesh *mesh = rna_mesh(ptr);
+ const int index = rna_MeshEdge_index_get(ptr);
+ const float *values = (const float *)CustomData_get_layer(&mesh->edata, CD_BWEIGHT);
+ return values == NULL ? 0.0f : values[index];
}
static void rna_MEdge_bevel_weight_set(PointerRNA *ptr, float value)
{
- MEdge *medge = (MEdge *)ptr->data;
- medge->bweight = round_fl_to_uchar_clamp(value * 255.0f);
+ Mesh *mesh = rna_mesh(ptr);
+ const int index = rna_MeshEdge_index_get(ptr);
+ float *values = (float *)CustomData_add_layer(
+ &mesh->edata, CD_BWEIGHT, CD_SET_DEFAULT, NULL, mesh->totedge);
+ values[index] = clamp_f(value, 0.0f, 1.0f);
}
static float rna_MEdge_crease_get(PointerRNA *ptr)
@@ -3854,6 +3872,18 @@ static void rna_def_mesh(BlenderRNA *brna)
RNA_def_property_boolean_funcs(prop, "rna_Mesh_has_custom_normals_get", NULL);
RNA_define_verify_sdna(true);
+ prop = RNA_def_property(srna, "has_bevel_weight_edge", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(
+ prop, "Has Edge Bevel Weight", "True if the mesh has an edge bevel weight layer");
+ RNA_def_property_boolean_funcs(prop, "rna_Mesh_has_edge_bevel_weight_get", NULL);
+
+ prop = RNA_def_property(srna, "has_bevel_weight_vertex", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(
+ prop, "Has Vertex Bevel Weight", "True if the mesh has an vertex bevel weight layer");
+ RNA_def_property_boolean_funcs(prop, "rna_Mesh_has_vertex_bevel_weight_get", NULL);
+
prop = RNA_def_property(srna, "texco_mesh", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "texcomesh");
RNA_def_property_flag(prop, PROP_EDITABLE);
@@ -3907,13 +3937,6 @@ static void rna_def_mesh(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_Mesh_update_vertmask");
/* customdata flags */
- prop = RNA_def_property(srna, "use_customdata_vertex_bevel", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "cd_flag", ME_CDFLAG_VERT_BWEIGHT);
- RNA_def_property_ui_text(prop, "Store Vertex Bevel Weight", "");
-
- prop = RNA_def_property(srna, "use_customdata_edge_bevel", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "cd_flag", ME_CDFLAG_EDGE_BWEIGHT);
- RNA_def_property_ui_text(prop, "Store Edge Bevel Weight", "");
prop = RNA_def_property(srna, "use_customdata_vertex_crease", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "cd_flag", ME_CDFLAG_VERT_CREASE);
diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c
index 7551f9d7096..6b1df3fc4d4 100644
--- a/source/blender/makesrna/intern/rna_mesh_api.c
+++ b/source/blender/makesrna/intern/rna_mesh_api.c
@@ -22,6 +22,7 @@
# include "DNA_mesh_types.h"
+# include "BKE_anim_data.h"
# include "BKE_mesh.h"
# include "BKE_mesh_mapping.h"
# include "BKE_mesh_runtime.h"
@@ -192,6 +193,7 @@ static void rna_Mesh_count_selected_items(Mesh *mesh, int r_count[3])
static void rna_Mesh_clear_geometry(Mesh *mesh)
{
BKE_mesh_clear_geometry(mesh);
+ BKE_animdata_free(&mesh->id, false);
DEG_id_tag_update(&mesh->id, ID_RECALC_GEOMETRY_ALL_MODES);
WM_main_add_notifier(NC_GEOM | ND_DATA, mesh);
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 0be1dd3117c..caeee35a80a 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -7190,18 +7190,18 @@ static void def_cmp_scale(StructRNA *srna)
PropertyRNA *prop;
static const EnumPropertyItem space_items[] = {
- {CMP_SCALE_RELATIVE, "RELATIVE", 0, "Relative", ""},
- {CMP_SCALE_ABSOLUTE, "ABSOLUTE", 0, "Absolute", ""},
- {CMP_SCALE_SCENEPERCENT, "SCENE_SIZE", 0, "Scene Size", ""},
- {CMP_SCALE_RENDERPERCENT, "RENDER_SIZE", 0, "Render Size", ""},
+ {CMP_NODE_SCALE_RELATIVE, "RELATIVE", 0, "Relative", ""},
+ {CMP_NODE_SCALE_ABSOLUTE, "ABSOLUTE", 0, "Absolute", ""},
+ {CMP_NODE_SCALE_RENDER_PERCENT, "SCENE_SIZE", 0, "Scene Size", ""},
+ {CMP_NODE_SCALE_RENDER_SIZE, "RENDER_SIZE", 0, "Render Size", ""},
{0, NULL, 0, NULL, NULL},
};
/* matching bgpic_camera_frame_items[] */
static const EnumPropertyItem space_frame_items[] = {
- {0, "STRETCH", 0, "Stretch", ""},
- {CMP_SCALE_RENDERSIZE_FRAME_ASPECT, "FIT", 0, "Fit", ""},
- {CMP_SCALE_RENDERSIZE_FRAME_ASPECT | CMP_SCALE_RENDERSIZE_FRAME_CROP, "CROP", 0, "Crop", ""},
+ {CMP_NODE_SCALE_RENDER_SIZE_STRETCH, "STRETCH", 0, "Stretch", ""},
+ {CMP_NODE_SCALE_RENDER_SIZE_FIT, "FIT", 0, "Fit", ""},
+ {CMP_NODE_SCALE_RENDER_SIZE_CROP, "CROP", 0, "Crop", ""},
{0, NULL, 0, NULL, NULL},
};
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index bcf1bd36539..7feff30968f 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -294,7 +294,7 @@ static void mesh_merge_transform(Mesh *result,
for (i = 0; i < cap_nverts; i++, mv++) {
mul_m4_v3(cap_offset, mv->co);
/* Reset MVert flags for caps */
- mv->flag = mv->bweight = 0;
+ mv->flag = 0;
}
/* We have to correct normals too, if we do not tag them as dirty later! */
@@ -560,8 +560,8 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, chunk_nloops);
CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, chunk_npolys);
- /* Subsurf for eg won't have mesh data in the custom data arrays.
- * now add mvert/medge/mpoly layers. */
+ /* Subdivision-surface for eg won't have mesh data in the custom-data arrays.
+ * Now add #MVert/#MEdge/#MPoly layers. */
if (!CustomData_has_layer(&mesh->vdata, CD_MVERT)) {
memcpy(result_verts, src_verts, sizeof(MVert) * mesh->totvert);
}
diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c
index ee9a2856ab0..668843188ab 100644
--- a/source/blender/modifiers/intern/MOD_bevel.c
+++ b/source/blender/modifiers/intern/MOD_bevel.c
@@ -74,6 +74,10 @@ static void requiredDataMask(Object *UNUSED(ob),
if (bmd->defgrp_name[0] != '\0') {
r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
}
+ if (bmd->lim_flags & MOD_BEVEL_WEIGHT) {
+ r_cddata_masks->vmask |= CD_MASK_BWEIGHT;
+ r_cddata_masks->emask |= CD_MASK_BWEIGHT;
+ }
}
/*
diff --git a/source/blender/modifiers/intern/MOD_solidify_extrude.c b/source/blender/modifiers/intern/MOD_solidify_extrude.c
index 343aa3920d9..1456254c31f 100644
--- a/source/blender/modifiers/intern/MOD_solidify_extrude.c
+++ b/source/blender/modifiers/intern/MOD_solidify_extrude.c
@@ -340,11 +340,6 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
MPoly *mpoly = BKE_mesh_polys_for_write(result);
MLoop *mloop = BKE_mesh_loops_for_write(result);
- if (do_bevel_convex) {
- /* Make sure bweight is enabled. */
- result->cd_flag |= ME_CDFLAG_EDGE_BWEIGHT;
- }
-
if (do_shell) {
CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, (int)verts_num);
CustomData_copy_data(&mesh->vdata, &result->vdata, 0, (int)verts_num, (int)verts_num);
@@ -392,6 +387,12 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, (int)polys_num);
}
+ float *result_edge_bweight = NULL;
+ if (do_bevel_convex) {
+ result_edge_bweight = CustomData_add_layer(
+ &result->edata, CD_BWEIGHT, CD_SET_DEFAULT, NULL, result->totedge);
+ }
+
/* initializes: (i_end, do_shell_align, mv). */
#define INIT_VERT_ARRAY_OFFSETS(test) \
if (((ofs_new >= ofs_orig) == do_flip) == test) { \
@@ -671,20 +672,18 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
for (uint i = 0; i < edges_num; i++) {
if (edge_users[i] == INVALID_PAIR) {
float angle = edge_angs[i];
- medge[i].bweight = (char)clamp_i(
- (int)medge[i].bweight + (int)((angle < M_PI ? clamp_f(bevel_convex, 0.0f, 1.0f) :
- clamp_f(bevel_convex, -1.0f, 0.0f)) *
- 255),
- 0,
- 255);
+ result_edge_bweight[i] = clamp_f(result_edge_bweight[i] +
+ (angle < M_PI ? clamp_f(bevel_convex, 0.0f, 1.0f) :
+ clamp_f(bevel_convex, -1.0f, 0.0f)),
+ 0.0f,
+ 1.0f);
if (do_shell) {
- medge[i + edges_num].bweight = (char)clamp_i(
- (int)medge[i + edges_num].bweight +
- (int)((angle > M_PI ? clamp_f(bevel_convex, 0.0f, 1.0f) :
- clamp_f(bevel_convex, -1.0f, 0.0f)) *
- 255),
+ result_edge_bweight[i + edges_num] = clamp_f(
+ result_edge_bweight[i + edges_num] + (angle > M_PI ?
+ clamp_f(bevel_convex, 0.0f, 1.0f) :
+ clamp_f(bevel_convex, -1.0f, 0.0f)),
0,
- 255);
+ 1.0f);
}
}
}
@@ -900,20 +899,17 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
for (i = 0; i < edges_num; i++) {
if (edge_users[i] == INVALID_PAIR) {
float angle = edge_angs[i];
- medge[i].bweight = (char)clamp_i(
- (int)medge[i].bweight + (int)((angle < M_PI ? clamp_f(bevel_convex, 0, 1) :
- clamp_f(bevel_convex, -1, 0)) *
- 255),
- 0,
- 255);
+ result_edge_bweight[i] = clamp_f(result_edge_bweight[i] +
+ (angle < M_PI ? clamp_f(bevel_convex, 0.0f, 1.0f) :
+ clamp_f(bevel_convex, -1.0f, 0.0f)),
+ 0.0f,
+ 1.0f);
if (do_shell) {
- medge[i + edges_num].bweight = (char)clamp_i(
- (int)medge[i + edges_num].bweight +
- (int)((angle > M_PI ? clamp_f(bevel_convex, 0, 1) :
- clamp_f(bevel_convex, -1, 0)) *
- 255),
- 0,
- 255);
+ result_edge_bweight[i + edges_num] = clamp_f(
+ result_edge_bweight[i + edges_num] +
+ (angle > M_PI ? clamp_f(bevel_convex, 0, 1) : clamp_f(bevel_convex, -1, 0)),
+ 0.0f,
+ 1.0f);
}
}
}
diff --git a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
index e73df0d1c12..d3aff5c58c5 100644
--- a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
+++ b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
@@ -189,6 +189,10 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
const MPoly *orig_mpoly = BKE_mesh_polys(mesh);
const MLoop *orig_mloop = BKE_mesh_loops(mesh);
+ /* These might be null. */
+ const float *orig_vert_bweight = CustomData_get_layer(&mesh->vdata, CD_BWEIGHT);
+ const float *orig_edge_bweight = CustomData_get_layer(&mesh->edata, CD_BWEIGHT);
+
uint new_verts_num = 0;
uint new_edges_num = 0;
uint new_loops_num = 0;
@@ -1965,9 +1969,10 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
int *origindex_edge = CustomData_get_layer(&result->edata, CD_ORIGINDEX);
int *origindex_poly = CustomData_get_layer(&result->pdata, CD_ORIGINDEX);
- if (bevel_convex != 0.0f || (result->cd_flag & ME_CDFLAG_VERT_BWEIGHT) != 0) {
- /* make sure bweight is enabled */
- result->cd_flag |= ME_CDFLAG_EDGE_BWEIGHT;
+ float *result_edge_bweight = CustomData_get_layer(&result->edata, CD_BWEIGHT);
+ if (bevel_convex != 0.0f || orig_vert_bweight != NULL) {
+ result_edge_bweight = CustomData_add_layer(
+ &result->edata, CD_BWEIGHT, CD_SET_DEFAULT, NULL, result->totedge);
}
/* Checks that result has dvert data. */
@@ -2038,17 +2043,18 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
medge[insert].v2 = v2;
medge[insert].flag = orig_medge[(*l)->old_edge].flag | ME_EDGEDRAW | ME_EDGERENDER;
medge[insert].crease = orig_medge[(*l)->old_edge].crease;
- medge[insert].bweight = orig_medge[(*l)->old_edge].bweight;
+ if (result_edge_bweight) {
+ result_edge_bweight[insert] = orig_edge_bweight[(*l)->old_edge];
+ }
if (bevel_convex != 0.0f && (*l)->faces[1] != NULL) {
- medge[insert].bweight = (char)clamp_i(
- (int)medge[insert].bweight + (int)(((*l)->angle > M_PI + FLT_EPSILON ?
- clamp_f(bevel_convex, 0.0f, 1.0f) :
- ((*l)->angle < M_PI - FLT_EPSILON ?
- clamp_f(bevel_convex, -1.0f, 0.0f) :
- 0)) *
- 255),
- 0,
- 255);
+ result_edge_bweight[insert] = clamp_f(
+ result_edge_bweight[insert] +
+ ((*l)->angle > M_PI + FLT_EPSILON ?
+ clamp_f(bevel_convex, 0.0f, 1.0f) :
+ ((*l)->angle < M_PI - FLT_EPSILON ? clamp_f(bevel_convex, -1.0f, 0.0f) :
+ 0)),
+ 0.0f,
+ 1.0f);
}
(*l)->new_edge = insert;
}
@@ -2113,13 +2119,14 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
EdgeGroup *last_g = NULL;
EdgeGroup *first_g = NULL;
char mv_crease = vertex_crease ? (char)(vertex_crease[i] * 255.0f) : 0;
+ float mv_bweight = orig_vert_bweight ? orig_vert_bweight[i] : 0.0f;
/* Data calculation cache. */
char max_crease;
char last_max_crease = 0;
char first_max_crease = 0;
- char max_bweight;
- char last_max_bweight = 0;
- char first_max_bweight = 0;
+ float max_bweight;
+ float last_max_bweight = 0.0f;
+ float first_max_bweight = 0.0f;
short flag;
short last_flag = 0;
short first_flag = 0;
@@ -2142,20 +2149,24 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
max_crease = ed->crease;
}
if (g->edges[k]->new_edge != MOD_SOLIDIFY_EMPTY_TAG) {
- char bweight = medge[g->edges[k]->new_edge].bweight;
- if (bweight > max_bweight) {
- max_bweight = bweight;
+ if (result_edge_bweight) {
+ float bweight = result_edge_bweight[g->edges[k]->new_edge];
+ if (bweight > max_bweight) {
+ max_bweight = bweight;
+ }
}
}
flag |= ed->flag;
}
}
- const char bweight_open_edge = min_cc(
- orig_medge[g->edges[0]->old_edge].bweight,
- orig_medge[g->edges[g->edges_len - 1]->old_edge].bweight);
+ const float bweight_open_edge =
+ orig_edge_bweight ?
+ min_ff(orig_edge_bweight[g->edges[0]->old_edge],
+ orig_edge_bweight[g->edges[g->edges_len - 1]->old_edge]) :
+ 0.0f;
if (bweight_open_edge > 0) {
- max_bweight = min_cc(bweight_open_edge, max_bweight);
+ max_bweight = min_ff(bweight_open_edge, max_bweight);
}
else {
if (bevel_convex < 0.0f) {
@@ -2183,8 +2194,11 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
medge[edge_index].flag = ME_EDGEDRAW | ME_EDGERENDER |
((last_flag | flag) & (ME_SEAM | ME_SHARP));
medge[edge_index].crease = max_cc(mv_crease, min_cc(last_max_crease, max_crease));
- medge[edge_index++].bweight = max_cc(mv->bweight,
- min_cc(last_max_bweight, max_bweight));
+ if (result_edge_bweight) {
+ result_edge_bweight[edge_index] = max_ff(mv_bweight,
+ min_ff(last_max_bweight, max_bweight));
+ }
+ edge_index++;
}
last_g = g;
last_max_crease = max_crease;
@@ -2212,8 +2226,11 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
((last_flag | first_flag) & (ME_SEAM | ME_SHARP));
medge[edge_index].crease = max_cc(mv_crease,
min_cc(last_max_crease, first_max_crease));
- medge[edge_index++].bweight = max_cc(mv->bweight,
- min_cc(last_max_bweight, first_max_bweight));
+ if (result_edge_bweight) {
+ result_edge_bweight[edge_index] = max_ff(
+ mv_bweight, min_ff(last_max_bweight, first_max_bweight));
+ }
+ edge_index++;
/* Loop data. */
int *loops = MEM_malloc_arrayN(j, sizeof(*loops), "loops in solidify");
diff --git a/source/blender/nodes/NOD_node_declaration.hh b/source/blender/nodes/NOD_node_declaration.hh
index d8b8c354230..42755b2e8dd 100644
--- a/source/blender/nodes/NOD_node_declaration.hh
+++ b/source/blender/nodes/NOD_node_declaration.hh
@@ -92,6 +92,10 @@ class SocketDeclaration {
* realtime_compositor::InputDescriptor for more information. */
int compositor_domain_priority_ = 0;
+ /** This input shouldn't be realized on the operation domain of the node. See
+ * realtime_compositor::InputDescriptor for more information. */
+ bool compositor_skip_realization_ = false;
+
/** This input expects a single value and can't operate on non-single values. See
* realtime_compositor::InputDescriptor for more information. */
bool compositor_expects_single_value_ = false;
@@ -133,6 +137,7 @@ class SocketDeclaration {
const OutputFieldDependency &output_field_dependency() const;
int compositor_domain_priority() const;
+ bool compositor_skip_realization() const;
bool compositor_expects_single_value() const;
protected:
@@ -257,6 +262,14 @@ class SocketDeclarationBuilder : public BaseSocketDeclarationBuilder {
return *(Self *)this;
}
+ /** This input shouldn't be realized on the operation domain of the node. See
+ * realtime_compositor::InputDescriptor for more information. */
+ Self &compositor_skip_realization(bool value = true)
+ {
+ decl_->compositor_skip_realization_ = value;
+ return *(Self *)this;
+ }
+
/** This input expects a single value and can't operate on non-single values. See
* realtime_compositor::InputDescriptor for more information. */
Self &compositor_expects_single_value(bool value = true)
@@ -460,6 +473,11 @@ inline int SocketDeclaration::compositor_domain_priority() const
return compositor_domain_priority_;
}
+inline bool SocketDeclaration::compositor_skip_realization() const
+{
+ return compositor_skip_realization_;
+}
+
inline bool SocketDeclaration::compositor_expects_single_value() const
{
return compositor_expects_single_value_;
diff --git a/source/blender/nodes/composite/nodes/node_composite_blur.cc b/source/blender/nodes/composite/nodes/node_composite_blur.cc
index cb1d93fe10b..630f18361e3 100644
--- a/source/blender/nodes/composite/nodes/node_composite_blur.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_blur.cc
@@ -5,12 +5,27 @@
* \ingroup cmpnodes
*/
+#include <cstdint>
+
+#include "BLI_array.hh"
+#include "BLI_assert.h"
+#include "BLI_index_range.hh"
+#include "BLI_math_base.hh"
+#include "BLI_math_vec_types.hh"
+#include "BLI_math_vector.hh"
+
#include "RNA_access.h"
#include "UI_interface.h"
#include "UI_resources.h"
+#include "RE_pipeline.h"
+
+#include "GPU_state.h"
+#include "GPU_texture.h"
+
#include "COM_node_operation.hh"
+#include "COM_utilities.hh"
#include "node_composite_util.hh"
@@ -18,6 +33,8 @@
namespace blender::nodes::node_composite_blur_cc {
+NODE_STORAGE_FUNCS(NodeBlurData)
+
static void cmp_node_blur_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
@@ -75,13 +92,395 @@ static void node_composit_buts_blur(uiLayout *layout, bContext *UNUSED(C), Point
using namespace blender::realtime_compositor;
+/* A helper class that computes and caches a 1D GPU texture containing the weights of the separable
+ * filter of the given type and radius. The filter is assumed to be symmetric, because the filter
+ * functions are all even functions. Consequently, only the positive half of the filter is computed
+ * and the shader takes that into consideration. */
+class SymmetricSeparableBlurWeights {
+ private:
+ float radius_ = 1.0f;
+ int type_ = R_FILTER_GAUSS;
+ GPUTexture *texture_ = nullptr;
+
+ public:
+ ~SymmetricSeparableBlurWeights()
+ {
+ if (texture_) {
+ GPU_texture_free(texture_);
+ }
+ }
+
+ /* Check if a texture containing the weights was already computed for the given filter type and
+ * radius. If such texture exists, do nothing, otherwise, free the already computed texture and
+ * recompute it with the given filter type and radius. */
+ void update(float radius, int type)
+ {
+ if (texture_ && type == type_ && radius == radius_) {
+ return;
+ }
+
+ if (texture_) {
+ GPU_texture_free(texture_);
+ }
+
+ /* The size of filter is double the radius plus 1, but since the filter is symmetric, we only
+ * compute half of it and no doubling happens. We add 1 to make sure the filter size is always
+ * odd and there is a center weight. */
+ const int size = math::ceil(radius) + 1;
+ Array<float> weights(size);
+
+ float sum = 0.0f;
+
+ /* First, compute the center weight. */
+ const float center_weight = RE_filter_value(type, 0.0f);
+ weights[0] = center_weight;
+ sum += center_weight;
+
+ /* Second, compute the other weights in the positive direction, making sure to add double the
+ * weight to the sum of weights because the filter is symmetric and we only loop over half of
+ * it. Skip the center weight already computed by dropping the front index. */
+ const float scale = radius > 0.0f ? 1.0f / radius : 0.0f;
+ for (const int i : weights.index_range().drop_front(1)) {
+ const float weight = RE_filter_value(type, i * scale);
+ weights[i] = weight;
+ sum += weight * 2.0f;
+ }
+
+ /* Finally, normalize the weights. */
+ for (const int i : weights.index_range()) {
+ weights[i] /= sum;
+ }
+
+ texture_ = GPU_texture_create_1d("Weights", size, 1, GPU_R16F, weights.data());
+
+ type_ = type;
+ radius_ = radius;
+ }
+
+ void bind_as_texture(GPUShader *shader, const char *texture_name)
+ {
+ const int texture_image_unit = GPU_shader_get_texture_binding(shader, texture_name);
+ GPU_texture_bind(texture_, texture_image_unit);
+ }
+
+ void unbind_as_texture()
+ {
+ GPU_texture_unbind(texture_);
+ }
+};
+
+/* A helper class that computes and caches a 2D GPU texture containing the weights of the filter of
+ * the given type and radius. The filter is assumed to be symmetric, because the filter functions
+ * are evaluated on the normalized distance to the center. Consequently, only the upper right
+ * quadrant are computed and the shader takes that into consideration. */
+class SymmetricBlurWeights {
+ private:
+ int type_ = R_FILTER_GAUSS;
+ float2 radius_ = float2(1.0f);
+ GPUTexture *texture_ = nullptr;
+
+ public:
+ ~SymmetricBlurWeights()
+ {
+ if (texture_) {
+ GPU_texture_free(texture_);
+ }
+ }
+
+ /* Check if a texture containing the weights was already computed for the given filter type and
+ * radius. If such texture exists, do nothing, otherwise, free the already computed texture and
+ * recompute it with the given filter type and radius. */
+ void update(float2 radius, int type)
+ {
+ if (texture_ && type == type_ && radius == radius_) {
+ return;
+ }
+
+ if (texture_) {
+ GPU_texture_free(texture_);
+ }
+
+ /* The full size of filter is double the radius plus 1, but since the filter is symmetric, we
+ * only compute a single quadrant of it and so no doubling happens. We add 1 to make sure the
+ * filter size is always odd and there is a center weight. */
+ const float2 scale = math::safe_divide(float2(1.0f), radius);
+ const int2 size = int2(math::ceil(radius)) + int2(1);
+ Array<float> weights(size.x * size.y);
+
+ float sum = 0.0f;
+
+ /* First, compute the center weight. */
+ const float center_weight = RE_filter_value(type, 0.0f);
+ weights[0] = center_weight;
+ sum += center_weight;
+
+ /* Then, compute the weights along the positive x axis, making sure to add double the weight to
+ * the sum of weights because the filter is symmetric and we only loop over the positive half
+ * of the x axis. Skip the center weight already computed by dropping the front index. */
+ for (const int x : IndexRange(size.x).drop_front(1)) {
+ const float weight = RE_filter_value(type, x * scale.x);
+ weights[x] = weight;
+ sum += weight * 2.0f;
+ }
+
+ /* Then, compute the weights along the positive y axis, making sure to add double the weight to
+ * the sum of weights because the filter is symmetric and we only loop over the positive half
+ * of the y axis. Skip the center weight already computed by dropping the front index. */
+ for (const int y : IndexRange(size.y).drop_front(1)) {
+ const float weight = RE_filter_value(type, y * scale.y);
+ weights[size.x * y] = weight;
+ sum += weight * 2.0f;
+ }
+
+ /* Then, compute the other weights in the upper right quadrant, making sure to add quadruple
+ * the weight to the sum of weights because the filter is symmetric and we only loop over one
+ * quadrant of it. Skip the weights along the y and x axis already computed by dropping the
+ * front index. */
+ for (const int y : IndexRange(size.y).drop_front(1)) {
+ for (const int x : IndexRange(size.x).drop_front(1)) {
+ const float weight = RE_filter_value(type, math::length(float2(x, y) * scale));
+ weights[size.x * y + x] = weight;
+ sum += weight * 4.0f;
+ }
+ }
+
+ /* Finally, normalize the weights. */
+ for (const int y : IndexRange(size.y)) {
+ for (const int x : IndexRange(size.x)) {
+ weights[size.x * y + x] /= sum;
+ }
+ }
+
+ texture_ = GPU_texture_create_2d("Weights", size.x, size.y, 1, GPU_R16F, weights.data());
+
+ type_ = type;
+ radius_ = radius;
+ }
+
+ void bind_as_texture(GPUShader *shader, const char *texture_name)
+ {
+ const int texture_image_unit = GPU_shader_get_texture_binding(shader, texture_name);
+ GPU_texture_bind(texture_, texture_image_unit);
+ }
+
+ void unbind_as_texture()
+ {
+ GPU_texture_unbind(texture_);
+ }
+};
+
class BlurOperation : public NodeOperation {
+ private:
+ /* Cached symmetric blur weights. */
+ SymmetricBlurWeights blur_weights_;
+ /* Cached symmetric blur weights for the separable horizontal pass. */
+ SymmetricSeparableBlurWeights blur_horizontal_weights_;
+ /* Cached symmetric blur weights for the separable vertical pass. */
+ SymmetricSeparableBlurWeights blur_vertical_weights_;
+
public:
using NodeOperation::NodeOperation;
void execute() override
{
- get_input("Image").pass_through(get_result("Image"));
+ if (is_identity()) {
+ get_input("Image").pass_through(get_result("Image"));
+ return;
+ }
+
+ if (use_separable_filter()) {
+ GPUTexture *horizontal_pass_result = execute_separable_blur_horizontal_pass();
+ execute_separable_blur_vertical_pass(horizontal_pass_result);
+ }
+ else {
+ execute_blur();
+ }
+ }
+
+ void execute_blur()
+ {
+ GPUShader *shader = shader_manager().get("compositor_symmetric_blur");
+ GPU_shader_bind(shader);
+
+ GPU_shader_uniform_1b(shader, "extend_bounds", get_extend_bounds());
+ GPU_shader_uniform_1b(shader, "gamma_correct", node_storage(bnode()).gamma);
+
+ const Result &input_image = get_input("Image");
+ input_image.bind_as_texture(shader, "input_tx");
+
+ blur_weights_.update(compute_blur_radius(), node_storage(bnode()).filtertype);
+ blur_weights_.bind_as_texture(shader, "weights_tx");
+
+ Domain domain = compute_domain();
+ if (get_extend_bounds()) {
+ /* Add a radius amount of pixels in both sides of the image, hence the multiply by 2. */
+ domain.size += int2(math::ceil(compute_blur_radius())) * 2;
+ }
+
+ Result &output_image = get_result("Image");
+ output_image.allocate_texture(domain);
+ output_image.bind_as_image(shader, "output_img");
+
+ compute_dispatch_threads_at_least(shader, domain.size);
+
+ GPU_shader_unbind();
+ output_image.unbind_as_image();
+ input_image.unbind_as_texture();
+ blur_weights_.unbind_as_texture();
+ }
+
+ GPUTexture *execute_separable_blur_horizontal_pass()
+ {
+ GPUShader *shader = shader_manager().get("compositor_symmetric_separable_blur");
+ GPU_shader_bind(shader);
+
+ GPU_shader_uniform_1b(shader, "extend_bounds", get_extend_bounds());
+ GPU_shader_uniform_1b(shader, "gamma_correct_input", node_storage(bnode()).gamma);
+ GPU_shader_uniform_1b(shader, "gamma_uncorrect_output", false);
+
+ const Result &input_image = get_input("Image");
+ input_image.bind_as_texture(shader, "input_tx");
+
+ blur_horizontal_weights_.update(compute_blur_radius().x, node_storage(bnode()).filtertype);
+ blur_horizontal_weights_.bind_as_texture(shader, "weights_tx");
+
+ Domain domain = compute_domain();
+ if (get_extend_bounds()) {
+ domain.size.x += static_cast<int>(math::ceil(compute_blur_radius().x)) * 2;
+ }
+
+ /* We allocate an output image of a transposed size, that is, with a height equivalent to the
+ * width of the input and vice versa. This is done as a performance optimization. The shader
+ * will blur the image horizontally and write it to the intermediate output transposed. Then
+ * the vertical pass will execute the same horizontal blur shader, but since its input is
+ * transposed, it will effectively do a vertical blur and write to the output transposed,
+ * effectively undoing the transposition in the horizontal pass. This is done to improve
+ * spatial cache locality in the shader and to avoid having two separate shaders for each blur
+ * pass. */
+ const int2 transposed_domain = int2(domain.size.y, domain.size.x);
+
+ GPUTexture *horizontal_pass_result = texture_pool().acquire_color(transposed_domain);
+ const int image_unit = GPU_shader_get_texture_binding(shader, "output_img");
+ GPU_texture_image_bind(horizontal_pass_result, image_unit);
+
+ compute_dispatch_threads_at_least(shader, domain.size);
+
+ GPU_shader_unbind();
+ input_image.unbind_as_texture();
+ blur_horizontal_weights_.unbind_as_texture();
+ GPU_texture_image_unbind(horizontal_pass_result);
+
+ return horizontal_pass_result;
+ }
+
+ void execute_separable_blur_vertical_pass(GPUTexture *horizontal_pass_result)
+ {
+ GPUShader *shader = shader_manager().get("compositor_symmetric_separable_blur");
+ GPU_shader_bind(shader);
+
+ GPU_shader_uniform_1b(shader, "extend_bounds", get_extend_bounds());
+ GPU_shader_uniform_1b(shader, "gamma_correct_input", false);
+ GPU_shader_uniform_1b(shader, "gamma_uncorrect_output", node_storage(bnode()).gamma);
+
+ GPU_memory_barrier(GPU_BARRIER_TEXTURE_FETCH);
+ const int texture_image_unit = GPU_shader_get_texture_binding(shader, "input_tx");
+ GPU_texture_bind(horizontal_pass_result, texture_image_unit);
+
+ blur_vertical_weights_.update(compute_blur_radius().y, node_storage(bnode()).filtertype);
+ blur_vertical_weights_.bind_as_texture(shader, "weights_tx");
+
+ Domain domain = compute_domain();
+ if (get_extend_bounds()) {
+ /* Add a radius amount of pixels in both sides of the image, hence the multiply by 2. */
+ domain.size += int2(math::ceil(compute_blur_radius())) * 2;
+ }
+
+ Result &output_image = get_result("Image");
+ output_image.allocate_texture(domain);
+ output_image.bind_as_image(shader, "output_img");
+
+ /* Notice that the domain is transposed, see the note on the horizontal pass method for more
+ * information on the reasoning behind this. */
+ compute_dispatch_threads_at_least(shader, int2(domain.size.y, domain.size.x));
+
+ GPU_shader_unbind();
+ output_image.unbind_as_image();
+ blur_vertical_weights_.unbind_as_texture();
+ GPU_texture_unbind(horizontal_pass_result);
+ }
+
+ float2 compute_blur_radius()
+ {
+ const float size = math::clamp(get_input("Size").get_float_value_default(1.0f), 0.0f, 1.0f);
+
+ if (!node_storage(bnode()).relative) {
+ return float2(node_storage(bnode()).sizex, node_storage(bnode()).sizey) * size;
+ }
+
+ int2 image_size = get_input("Image").domain().size;
+ switch (node_storage(bnode()).aspect) {
+ case CMP_NODE_BLUR_ASPECT_Y:
+ image_size.y = image_size.x;
+ break;
+ case CMP_NODE_BLUR_ASPECT_X:
+ image_size.x = image_size.y;
+ break;
+ default:
+ BLI_assert(node_storage(bnode()).aspect == CMP_NODE_BLUR_ASPECT_NONE);
+ break;
+ }
+
+ return float2(image_size) * get_size_factor() * size;
+ }
+
+ /* Returns true if the operation does nothing and the input can be passed through. */
+ bool is_identity()
+ {
+ const Result &input = get_input("Image");
+ /* Single value inputs can't be blurred and are returned as is. */
+ if (input.is_single_value()) {
+ return true;
+ }
+
+ /* Zero blur radius. The operation does nothing and the input can be passed through. */
+ if (compute_blur_radius() == float2(0.0)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /* The blur node can operate with different filter types, evaluated on the normalized distance to
+ * the center of the filter. Some of those filters are separable and can be computed as such. If
+ * the bokeh member is disabled in the node, then the filter is always computed as separable even
+ * if it is not in fact separable, in which case, the used filter is a cheaper approximation to
+ * the actual filter. If the bokeh member is enabled, then the filter is computed as separable if
+ * it is in fact separable and as a normal 2D filter otherwise. */
+ bool use_separable_filter()
+ {
+ if (!node_storage(bnode()).bokeh) {
+ return true;
+ }
+
+ /* Both Box and Gaussian filters are separable. The rest is not. */
+ switch (node_storage(bnode()).filtertype) {
+ case R_FILTER_BOX:
+ case R_FILTER_GAUSS:
+ case R_FILTER_FAST_GAUSS:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ float2 get_size_factor()
+ {
+ return float2(node_storage(bnode()).percentx, node_storage(bnode()).percenty) / 100.0f;
+ }
+
+ bool get_extend_bounds()
+ {
+ return bnode().custom1 & CMP_NODEFLAG_BLUR_EXTEND_BOUNDS;
}
};
diff --git a/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc b/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc
index 538f00af12d..182169405de 100644
--- a/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc
@@ -5,10 +5,16 @@
* \ingroup cmpnodes
*/
+#include "BLI_math_base.hh"
+#include "BLI_math_vec_types.hh"
+
#include "UI_interface.h"
#include "UI_resources.h"
+#include "GPU_texture.h"
+
#include "COM_node_operation.hh"
+#include "COM_utilities.hh"
#include "node_composite_util.hh"
@@ -18,10 +24,22 @@ namespace blender::nodes::node_composite_bokehblur_cc {
static void cmp_node_bokehblur_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>(N_("Image")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
- b.add_input<decl::Color>(N_("Bokeh")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_input<decl::Float>(N_("Size")).default_value(1.0f).min(0.0f).max(10.0f);
- b.add_input<decl::Float>(N_("Bounding box")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_input<decl::Color>(N_("Image"))
+ .default_value({0.8f, 0.8f, 0.8f, 1.0f})
+ .compositor_domain_priority(0);
+ b.add_input<decl::Color>(N_("Bokeh"))
+ .default_value({1.0f, 1.0f, 1.0f, 1.0f})
+ .compositor_skip_realization();
+ b.add_input<decl::Float>(N_("Size"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(10.0f)
+ .compositor_domain_priority(1);
+ b.add_input<decl::Float>(N_("Bounding box"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .compositor_domain_priority(2);
b.add_output<decl::Color>(N_("Image"));
}
@@ -47,7 +65,82 @@ class BokehBlurOperation : public NodeOperation {
void execute() override
{
- get_input("Image").pass_through(get_result("Image"));
+ if (is_identity()) {
+ get_input("Image").pass_through(get_result("Image"));
+ return;
+ }
+
+ GPUShader *shader = shader_manager().get("compositor_blur");
+ GPU_shader_bind(shader);
+
+ GPU_shader_uniform_1i(shader, "radius", compute_blur_radius());
+ GPU_shader_uniform_1b(shader, "extend_bounds", get_extend_bounds());
+
+ const Result &input_image = get_input("Image");
+ input_image.bind_as_texture(shader, "input_tx");
+
+ const Result &input_weights = get_input("Bokeh");
+ input_weights.bind_as_texture(shader, "weights_tx");
+
+ const Result &input_mask = get_input("Bounding box");
+ input_mask.bind_as_texture(shader, "mask_tx");
+
+ Domain domain = compute_domain();
+ if (get_extend_bounds()) {
+ /* Add a radius amount of pixels in both sides of the image, hence the multiply by 2. */
+ domain.size += int2(compute_blur_radius() * 2);
+ }
+
+ Result &output_image = get_result("Image");
+ output_image.allocate_texture(domain);
+ output_image.bind_as_image(shader, "output_img");
+
+ compute_dispatch_threads_at_least(shader, domain.size);
+
+ GPU_shader_unbind();
+ output_image.unbind_as_image();
+ input_image.unbind_as_texture();
+ input_weights.unbind_as_texture();
+ input_mask.unbind_as_texture();
+ }
+
+ int compute_blur_radius()
+ {
+ const int2 image_size = get_input("Image").domain().size;
+ const int max_size = math::max(image_size.x, image_size.y);
+
+ /* The [0, 10] range of the size is arbitrary and is merely in place to avoid very long
+ * computations of the bokeh blur. */
+ const float size = math::clamp(get_input("Size").get_float_value_default(1.0f), 0.0f, 10.0f);
+
+ /* The 100 divisor is arbitrary and was chosen using visual judgement. */
+ return size * (max_size / 100.0f);
+ }
+
+ bool is_identity()
+ {
+ const Result &input = get_input("Image");
+ if (input.is_single_value()) {
+ return true;
+ }
+
+ if (compute_blur_radius() == 0) {
+ return true;
+ }
+
+ /* This input is, in fact, a boolean mask. If it is zero, no blurring will take place.
+ * Otherwise, the blurring will take place ignoring the value of the input entirely. */
+ const Result &bounding_box = get_input("Bounding box");
+ if (bounding_box.is_single_value() && bounding_box.get_float_value() == 0.0) {
+ return true;
+ }
+
+ return false;
+ }
+
+ bool get_extend_bounds()
+ {
+ return bnode().custom1 & CMP_NODEFLAG_BLUR_EXTEND_BOUNDS;
}
};
diff --git a/source/blender/nodes/composite/nodes/node_composite_pixelate.cc b/source/blender/nodes/composite/nodes/node_composite_pixelate.cc
index 4567464a547..c4e42f8247d 100644
--- a/source/blender/nodes/composite/nodes/node_composite_pixelate.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_pixelate.cc
@@ -5,6 +5,9 @@
* \ingroup cmpnodes
*/
+#include "BLI_math_vec_types.hh"
+#include "BLI_math_vector.hh"
+
#include "COM_node_operation.hh"
#include "node_composite_util.hh"
@@ -27,8 +30,34 @@ class PixelateOperation : public NodeOperation {
void execute() override
{
+ /* It might seems strange that the input is passed through without any processing, but note
+ * that the actual processing happens inside the domain realization input processor of the
+ * input. Indeed, the pixelate node merely realizes its input on a smaller-sized domain that
+ * matches its apparent size, that is, its size after the domain transformation. The pixelate
+ * node has no effect if the input is scaled-up. See the compute_domain method for more
+ * information. */
get_input("Color").pass_through(get_result("Color"));
}
+
+ /* Compute a smaller-sized domain that matches the apparent size of the input while having a unit
+ * scale transformation, see the execute method for more information. */
+ Domain compute_domain() override
+ {
+ Domain domain = get_input("Color").domain();
+
+ /* Get the scaling component of the domain transformation, but make sure it doesn't exceed 1,
+ * because pixelation should only happen if the input is scaled down. */
+ const float2 scale = math::min(float2(1.0f), domain.transformation.scale_2d());
+
+ /* Multiply the size of the domain by its scale to match its apparent size, but make sure it is
+ * at least 1 pixel in both axis. */
+ domain.size = math::max(int2(float2(domain.size) * scale), int2(1));
+
+ /* Reset the scale of the transformation by transforming it with the inverse of the scale. */
+ domain.transformation *= float3x3::from_scale(math::safe_divide(float2(1.0f), scale));
+
+ return domain;
+ }
};
static NodeOperation *get_compositor_operation(Context &context, DNode node)
diff --git a/source/blender/nodes/composite/nodes/node_composite_scale.cc b/source/blender/nodes/composite/nodes/node_composite_scale.cc
index 8b43ae8c9ca..eb2d7162c69 100644
--- a/source/blender/nodes/composite/nodes/node_composite_scale.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_scale.cc
@@ -5,6 +5,11 @@
* \ingroup cmpnodes
*/
+#include "BLI_assert.h"
+#include "BLI_float3x3.hh"
+#include "BLI_math_base.hh"
+#include "BLI_math_vec_types.hh"
+
#include "RNA_access.h"
#include "UI_interface.h"
@@ -20,16 +25,26 @@ namespace blender::nodes::node_composite_scale_cc {
static void cmp_node_scale_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_input<decl::Float>(N_("X")).default_value(1.0f).min(0.0001f).max(CMP_SCALE_MAX);
- b.add_input<decl::Float>(N_("Y")).default_value(1.0f).min(0.0001f).max(CMP_SCALE_MAX);
+ b.add_input<decl::Color>(N_("Image"))
+ .default_value({1.0f, 1.0f, 1.0f, 1.0f})
+ .compositor_domain_priority(0);
+ b.add_input<decl::Float>(N_("X"))
+ .default_value(1.0f)
+ .min(0.0001f)
+ .max(CMP_SCALE_MAX)
+ .compositor_expects_single_value();
+ b.add_input<decl::Float>(N_("Y"))
+ .default_value(1.0f)
+ .min(0.0001f)
+ .max(CMP_SCALE_MAX)
+ .compositor_expects_single_value();
b.add_output<decl::Color>(N_("Image"));
}
static void node_composite_update_scale(bNodeTree *ntree, bNode *node)
{
bNodeSocket *sock;
- bool use_xy_scale = ELEM(node->custom1, CMP_SCALE_RELATIVE, CMP_SCALE_ABSOLUTE);
+ bool use_xy_scale = ELEM(node->custom1, CMP_NODE_SCALE_RELATIVE, CMP_NODE_SCALE_ABSOLUTE);
/* Only show X/Y scale factor inputs for modes using them! */
for (sock = (bNodeSocket *)node->inputs.first; sock; sock = sock->next) {
@@ -43,7 +58,7 @@ static void node_composit_buts_scale(uiLayout *layout, bContext *UNUSED(C), Poin
{
uiItemR(layout, ptr, "space", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
- if (RNA_enum_get(ptr, "space") == CMP_SCALE_RENDERPERCENT) {
+ if (RNA_enum_get(ptr, "space") == CMP_NODE_SCALE_RENDER_SIZE) {
uiLayout *row;
uiItemR(layout,
ptr,
@@ -65,7 +80,129 @@ class ScaleOperation : public NodeOperation {
void execute() override
{
- get_input("Image").pass_through(get_result("Image"));
+ Result &input = get_input("Image");
+ Result &result = get_result("Image");
+ input.pass_through(result);
+
+ const float3x3 transformation = float3x3::from_translation_rotation_scale(
+ get_translation(), 0.0f, get_scale());
+
+ result.transform(transformation);
+ result.get_realization_options().interpolation = Interpolation::Bilinear;
+ }
+
+ float2 get_scale()
+ {
+ switch (get_scale_method()) {
+ case CMP_NODE_SCALE_RELATIVE:
+ return get_scale_relative();
+ case CMP_NODE_SCALE_ABSOLUTE:
+ return get_scale_absolute();
+ case CMP_NODE_SCALE_RENDER_PERCENT:
+ return get_scale_render_percent();
+ case CMP_NODE_SCALE_RENDER_SIZE:
+ return get_scale_render_size();
+ default:
+ BLI_assert_unreachable();
+ return float2(1.0f);
+ }
+ }
+
+ /* Scale by the input factors. */
+ float2 get_scale_relative()
+ {
+ return float2(get_input("X").get_float_value_default(1.0f),
+ get_input("Y").get_float_value_default(1.0f));
+ }
+
+ /* Scale such that the new size matches the input absolute size. */
+ float2 get_scale_absolute()
+ {
+ const float2 input_size = float2(get_input("Image").domain().size);
+ const float2 absolute_size = float2(get_input("X").get_float_value_default(1.0f),
+ get_input("Y").get_float_value_default(1.0f));
+ return absolute_size / input_size;
+ }
+
+ /* Scale by the render resolution percentage. */
+ float2 get_scale_render_percent()
+ {
+ return float2(context().get_scene()->r.size / 100.0f);
+ }
+
+ float2 get_scale_render_size()
+ {
+ switch (get_scale_render_size_method()) {
+ case CMP_NODE_SCALE_RENDER_SIZE_STRETCH:
+ return get_scale_render_size_stretch();
+ case CMP_NODE_SCALE_RENDER_SIZE_FIT:
+ return get_scale_render_size_fit();
+ case CMP_NODE_SCALE_RENDER_SIZE_CROP:
+ return get_scale_render_size_crop();
+ default:
+ BLI_assert_unreachable();
+ return float2(1.0f);
+ }
+ }
+
+ /* Scale such that the new size matches the render size. Since the input is freely scaled, it is
+ * potentially stretched, hence the name. */
+ float2 get_scale_render_size_stretch()
+ {
+ const float2 input_size = float2(get_input("Image").domain().size);
+ const float2 render_size = float2(context().get_output_size());
+ return render_size / input_size;
+ }
+
+ /* Scale such that the dimension with the smaller scaling factor matches that of the render size
+ * while maintaining the input's aspect ratio. Since the other dimension is guaranteed not to
+ * exceed the render size region due to its larger scaling factor, the image is said to be fit
+ * inside that region, hence the name. */
+ float2 get_scale_render_size_fit()
+ {
+ const float2 input_size = float2(get_input("Image").domain().size);
+ const float2 render_size = float2(context().get_output_size());
+ const float2 scale = render_size / input_size;
+ return float2(math::min(scale.x, scale.y));
+ }
+
+ /* Scale such that the dimension with the larger scaling factor matches that of the render size
+ * while maintaining the input's aspect ratio. Since the other dimension is guaranteed to exceed
+ * the render size region due to its lower scaling factor, the image will be cropped inside that
+ * region, hence the name. */
+ float2 get_scale_render_size_crop()
+ {
+ const float2 input_size = float2(get_input("Image").domain().size);
+ const float2 render_size = float2(context().get_output_size());
+ const float2 scale = render_size / input_size;
+ return float2(math::max(scale.x, scale.y));
+ }
+
+ float2 get_translation()
+ {
+ /* Only the render size option supports offset translation. */
+ if (get_scale_method() != CMP_NODE_SCALE_RENDER_SIZE) {
+ return float2(0.0f);
+ }
+
+ /* Translate by the offset factor relative to the new size. */
+ const float2 input_size = float2(get_input("Image").domain().size);
+ return get_offset() * input_size * get_scale();
+ }
+
+ CMPNodeScaleMethod get_scale_method()
+ {
+ return (CMPNodeScaleMethod)bnode().custom1;
+ }
+
+ CMPNodeScaleRenderSizeMethod get_scale_render_size_method()
+ {
+ return (CMPNodeScaleRenderSizeMethod)bnode().custom2;
+ }
+
+ float2 get_offset()
+ {
+ return float2(bnode().custom3, bnode().custom4);
}
};
diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c
index 939473ceaa0..a0129157b95 100644
--- a/source/blender/python/intern/bpy_app.c
+++ b/source/blender/python/intern/bpy_app.c
@@ -79,8 +79,6 @@ static PyStructSequence_Field app_info_fields[] = {
{"version_string", "The Blender version formatted as a string"},
{"version_cycle", "The release status of this build alpha/beta/rc/release"},
{"version_char", "Deprecated, always an empty string"},
- {"binary_path",
- "The location of Blender's executable, useful for utilities that open new instances"},
{"background",
"Boolean, True when blender is running without a user interface (started with -b)"},
{"factory_startup", "Boolean, True when blender is running with --factory-startup)"},
@@ -151,7 +149,6 @@ static PyObject *make_app_info(void)
SetStrItem(STRINGIFY(BLENDER_VERSION_CYCLE));
SetStrItem("");
- SetStrItem(BKE_appdir_program_path());
SetObjItem(PyBool_FromLong(G.background));
SetObjItem(PyBool_FromLong(G.factory_startup));
@@ -345,6 +342,33 @@ static PyObject *bpy_app_autoexec_fail_message_get(PyObject *UNUSED(self), void
return PyC_UnicodeFromByte(G.autoexec_fail);
}
+PyDoc_STRVAR(bpy_app_binary_path_doc,
+ "The location of Blender's executable, useful for utilities that open new instances. "
+ "Read-only unless Blender is built as a Python module - in this case the value is "
+ "an empty string which script authors may point to a Blender binary.");
+static PyObject *bpy_app_binary_path_get(PyObject *UNUSED(self), void *UNUSED(closure))
+{
+ return PyC_UnicodeFromByte(BKE_appdir_program_path());
+}
+
+static int bpy_app_binary_path_set(PyObject *UNUSED(self), PyObject *value, void *UNUSED(closure))
+{
+#ifndef WITH_PYTHON_MODULE
+ PyErr_SetString(PyExc_AttributeError,
+ "bpy.app.binary_path is only writable when built as a Python module");
+ return -1;
+#endif
+ PyObject *value_coerce = NULL;
+ const char *filepath = PyC_UnicodeAsByte(value, &value_coerce);
+ if (filepath == NULL) {
+ PyErr_Format(PyExc_ValueError, "expected a string or bytes, got %s", Py_TYPE(value)->tp_name);
+ return -1;
+ }
+ BKE_appdir_program_path_init(filepath);
+ Py_XDECREF(value_coerce);
+ return 0;
+}
+
static PyGetSetDef bpy_app_getsets[] = {
{"debug", bpy_app_debug_get, bpy_app_debug_set, bpy_app_debug_doc, (void *)G_DEBUG},
{"debug_ffmpeg",
@@ -450,7 +474,14 @@ static PyGetSetDef bpy_app_getsets[] = {
(void *)G_FLAG_SCRIPT_AUTOEXEC_FAIL_QUIET},
{"autoexec_fail_message", bpy_app_autoexec_fail_message_get, NULL, NULL, NULL},
- /* End-of-list marker. */
+ /* Support script authors setting the Blender binary path to use, otherwise this value
+ * is not known when built as a Python module. */
+ {"binary_path",
+ bpy_app_binary_path_get,
+ bpy_app_binary_path_set,
+ bpy_app_binary_path_doc,
+ NULL},
+
{NULL, NULL, NULL, NULL, NULL},
};
diff --git a/source/blender/render/intern/initrender.cc b/source/blender/render/intern/initrender.cc
index cc05aa8621e..1ea93cbf6c8 100644
--- a/source/blender/render/intern/initrender.cc
+++ b/source/blender/render/intern/initrender.cc
@@ -124,7 +124,8 @@ float RE_filter_value(int type, float x)
}
return 1.0f - x;
- case R_FILTER_GAUSS: {
+ case R_FILTER_GAUSS:
+ case R_FILTER_FAST_GAUSS: {
const float two_gaussfac2 = 2.0f * gaussfac * gaussfac;
x *= 3.0f * gaussfac;
return 1.0f / sqrtf((float)M_PI * two_gaussfac2) * expf(-x * x / two_gaussfac2);
diff --git a/source/blender/render/intern/render_result.cc b/source/blender/render/intern/render_result.cc
index 86ee9ad779a..50eb7e9f2d2 100644
--- a/source/blender/render/intern/render_result.cc
+++ b/source/blender/render/intern/render_result.cc
@@ -929,7 +929,11 @@ int render_result_exr_file_read_path(RenderResult *rr,
return 1;
}
-static void render_result_exr_file_cache_path(Scene *sce, const char *root, char *r_path)
+#define FILE_CACHE_MAX (FILE_MAXFILE + FILE_MAXFILE + MAX_ID_NAME + 100)
+
+static void render_result_exr_file_cache_path(Scene *sce,
+ const char *root,
+ char r_path[FILE_CACHE_MAX])
{
char filename_full[FILE_MAX + MAX_ID_NAME + 100], filename[FILE_MAXFILE], dirname[FILE_MAXDIR];
char path_digest[16] = {0};
@@ -959,13 +963,17 @@ static void render_result_exr_file_cache_path(Scene *sce, const char *root, char
filename,
sce->id.name + 2,
path_hexdigest);
- BLI_make_file_string(dirname, r_path, root, filename_full);
+
+ BLI_join_dirfile(r_path, FILE_CACHE_MAX, root, filename_full);
+ if (BLI_path_is_rel(r_path)) {
+ BLI_path_abs(r_path, dirname);
+ }
}
void render_result_exr_file_cache_write(Render *re)
{
RenderResult *rr = re->result;
- char str[FILE_MAXFILE + FILE_MAXFILE + MAX_ID_NAME + 100];
+ char str[FILE_CACHE_MAX];
char *root = U.render_cachedir;
render_result_passes_allocated_ensure(rr);
@@ -979,7 +987,7 @@ void render_result_exr_file_cache_write(Render *re)
bool render_result_exr_file_cache_read(Render *re)
{
/* File path to cache. */
- char filepath[FILE_MAXFILE + MAX_ID_NAME + MAX_ID_NAME + 100] = "";
+ char filepath[FILE_CACHE_MAX] = "";
char *root = U.render_cachedir;
render_result_exr_file_cache_path(re->scene, root, filepath);
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index 13c1579d24b..186edfe68d6 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -1899,7 +1899,7 @@ static bool wm_file_write(bContext *C,
/** \name Auto-Save API
* \{ */
-static void wm_autosave_location(char *filepath)
+static void wm_autosave_location(char filepath[FILE_MAX])
{
const int pid = abs(getpid());
char path[1024];
@@ -1918,23 +1918,22 @@ static void wm_autosave_location(char *filepath)
BLI_snprintf(path, sizeof(path), "%d_autosave.blend", pid);
}
+ const char *tempdir_base = BKE_tempdir_base();
#ifdef WIN32
- /* XXX Need to investigate how to handle default location of '/tmp/'
- * This is a relative directory on Windows, and it may be
- * found. Example:
- * Blender installed on D:\ drive, D:\ drive has D:\tmp\
- * Now, BLI_exists() will find '/tmp/' exists, but
- * BLI_make_file_string will create string that has it most likely on C:\
- * through BLI_windows_get_default_root_dir().
- * If there is no C:\tmp autosave fails. */
- if (!BLI_exists(BKE_tempdir_base())) {
+ /* XXX Need to investigate how to handle default location of `/tmp/`
+ * This is a relative directory on Windows, and it may be found. Example:
+ * Blender installed on `D:\` drive, `D:\` drive has `D:\tmp\` Now, `BLI_exists()`
+ * will find `/tmp/` exists, but #BLI_windows_get_default_root_dir will expand this to `C:\`.
+ * If there is no `C:\tmp` autosave fails. */
+ if (!BLI_exists(tempdir_base)) {
const char *savedir = BKE_appdir_folder_id_create(BLENDER_USER_AUTOSAVE, NULL);
- BLI_make_file_string("/", filepath, savedir, path);
- return;
+ if (savedir) {
+ tempdir_base = savedir;
+ }
}
#endif
- BLI_join_dirfile(filepath, FILE_MAX, BKE_tempdir_base(), path);
+ BLI_join_dirfile(filepath, FILE_MAX, tempdir_base, path);
}
static void wm_autosave_write(Main *bmain, wmWindowManager *wm)
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 8163b39b3dd..283b87f1a2f 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -634,13 +634,15 @@ void WM_exit_ex(bContext *C, const bool do_python)
BKE_sound_exit();
BKE_appdir_exit();
- CLG_exit();
BKE_blender_atexit();
wm_autosave_delete();
BKE_tempdir_session_purge();
+
+ /* Keep last (or near last) so logging can be used right up until everything is shut-down. */
+ CLG_exit();
}
void WM_exit(bContext *C)