diff options
Diffstat (limited to 'source/blender')
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) |