diff options
Diffstat (limited to 'source/blender')
723 files changed, 19382 insertions, 7866 deletions
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt index da6df831c0a..efd30ba8509 100644 --- a/source/blender/CMakeLists.txt +++ b/source/blender/CMakeLists.txt @@ -23,7 +23,9 @@ set(SRC_DNA_INC ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_action_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_anim_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_armature_types.h + ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_asset_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_boid_types.h + ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_brush_enums.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_brush_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_cachefile_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_camera_types.h diff --git a/source/blender/blenfont/intern/blf_dir.c b/source/blender/blenfont/intern/blf_dir.c index 51d3849aa48..25235097505 100644 --- a/source/blender/blenfont/intern/blf_dir.c +++ b/source/blender/blenfont/intern/blf_dir.c @@ -47,6 +47,9 @@ #include "blf_internal.h" #include "blf_internal_types.h" +#include "BKE_global.h" +#include "BKE_main.h" + static ListBase global_font_dir = {NULL, NULL}; static DirBLF *blf_dir_find(const char *path) @@ -137,9 +140,11 @@ char *blf_dir_search(const char *file) } if (!s) { - /* check the current directory, why not ? */ - if (BLI_exists(file)) { - s = BLI_strdup(file); + /* Assume file is either an abslute path, or a relative path to current directory. */ + BLI_strncpy(full_path, file, sizeof(full_path)); + BLI_path_abs(full_path, BKE_main_blendfile_path(G_MAIN)); + if (BLI_exists(full_path)) { + s = BLI_strdup(full_path); } } diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index d8605941974..717cfa607ad 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -30,10 +30,10 @@ extern "C" { #endif -struct BlendWriter; struct BlendDataReader; -struct BlendLibReader; struct BlendExpander; +struct BlendLibReader; +struct BlendWriter; struct bArmature; /* The following structures are defined in DNA_action_types.h, and DNA_anim_types.h */ diff --git a/source/blender/blenkernel/BKE_anim_visualization.h b/source/blender/blenkernel/BKE_anim_visualization.h index decb2e0b210..4e86abeed8d 100644 --- a/source/blender/blenkernel/BKE_anim_visualization.h +++ b/source/blender/blenkernel/BKE_anim_visualization.h @@ -26,14 +26,14 @@ extern "C" { #endif +struct BlendDataReader; +struct BlendWriter; struct Object; struct ReportList; struct Scene; struct bAnimVizSettings; struct bMotionPath; struct bPoseChannel; -struct BlendWriter; -struct BlendDataReader; /* ---------------------------------------------------- */ /* Animation Visualization */ diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h index e812d04c7d1..8d904bd6019 100644 --- a/source/blender/blenkernel/BKE_animsys.h +++ b/source/blender/blenkernel/BKE_animsys.h @@ -45,8 +45,6 @@ struct NlaKeyframingContext; struct PathResolvedRNA; struct PointerRNA; struct PropertyRNA; -struct ReportList; -struct Scene; struct bAction; struct bActionGroup; struct bContext; diff --git a/source/blender/blenkernel/BKE_appdir.h b/source/blender/blenkernel/BKE_appdir.h index 6da6079ea2a..c9d671597e8 100644 --- a/source/blender/blenkernel/BKE_appdir.h +++ b/source/blender/blenkernel/BKE_appdir.h @@ -31,6 +31,8 @@ void BKE_appdir_exit(void); /* note on naming: typical _get() suffix is omitted here, * since its the main purpose of the API. */ const char *BKE_appdir_folder_default(void); +const char *BKE_appdir_folder_home(void); +bool BKE_appdir_folder_documents(char *dir); bool BKE_appdir_folder_id_ex(const int folder_id, const char *subfolder, char *path, diff --git a/source/blender/blenkernel/BKE_asset.h b/source/blender/blenkernel/BKE_asset.h new file mode 100644 index 00000000000..38cd5747343 --- /dev/null +++ b/source/blender/blenkernel/BKE_asset.h @@ -0,0 +1,59 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __BKE_ASSET_H__ +#define __BKE_ASSET_H__ + +/** \file + * \ingroup bke + */ + +#include "BLI_utildefines.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct BlendDataReader; +struct BlendWriter; +struct ID; +struct PreviewImage; + +struct AssetMetaData *BKE_asset_metadata_create(void); +void BKE_asset_metadata_free(struct AssetMetaData **asset_data); + +struct AssetTagEnsureResult { + struct AssetTag *tag; + /* Set to false if a tag of this name was already present. */ + bool is_new; +}; + +struct AssetTag *BKE_asset_metadata_tag_add(struct AssetMetaData *asset_data, const char *name); +struct AssetTagEnsureResult BKE_asset_metadata_tag_ensure(struct AssetMetaData *asset_data, + const char *name); +void BKE_asset_metadata_tag_remove(struct AssetMetaData *asset_data, struct AssetTag *tag); + +struct PreviewImage *BKE_asset_metadata_preview_get_from_id(const struct AssetMetaData *asset_data, + const struct ID *owner_id); + +void BKE_asset_metadata_write(struct BlendWriter *writer, struct AssetMetaData *asset_data); +void BKE_asset_metadata_read(struct BlendDataReader *reader, struct AssetMetaData *asset_data); + +#ifdef __cplusplus +} +#endif + +#endif /* __BKE_ASSET_H__ */ diff --git a/source/blender/blenkernel/BKE_attribute.h b/source/blender/blenkernel/BKE_attribute.h index 55a841d8fd1..574d9904dc4 100644 --- a/source/blender/blenkernel/BKE_attribute.h +++ b/source/blender/blenkernel/BKE_attribute.h @@ -35,7 +35,6 @@ extern "C" { struct CustomData; struct CustomDataLayer; struct ID; -struct PointerRNA; struct ReportList; /* Attribute.domain */ diff --git a/source/blender/blenkernel/BKE_attribute_access.hh b/source/blender/blenkernel/BKE_attribute_access.hh index c4a704ef385..22e14e44bec 100644 --- a/source/blender/blenkernel/BKE_attribute_access.hh +++ b/source/blender/blenkernel/BKE_attribute_access.hh @@ -26,8 +26,6 @@ #include "BLI_color.hh" #include "BLI_float3.hh" -struct Mesh; - namespace blender::bke { using fn::CPPType; @@ -266,11 +264,15 @@ template<typename T> class TypedWriteAttribute { } }; +using BooleanReadAttribute = TypedReadAttribute<bool>; using FloatReadAttribute = TypedReadAttribute<float>; using Float3ReadAttribute = TypedReadAttribute<float3>; +using Int32ReadAttribute = TypedReadAttribute<int>; using Color4fReadAttribute = TypedReadAttribute<Color4f>; +using BooleanWriteAttribute = TypedWriteAttribute<bool>; using FloatWriteAttribute = TypedWriteAttribute<float>; using Float3WriteAttribute = TypedWriteAttribute<float3>; +using Int32WriteAttribute = TypedWriteAttribute<int>; using Color4fWriteAttribute = TypedWriteAttribute<Color4f>; } // namespace blender::bke diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 2ec9e0048a6..1ed4d1183a1 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -39,7 +39,7 @@ extern "C" { /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 5 +#define BLENDER_FILE_SUBVERSION 8 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and show a warning if the file diff --git a/source/blender/blenkernel/BKE_boids.h b/source/blender/blenkernel/BKE_boids.h index c9e6f0e7346..71a4d35767f 100644 --- a/source/blender/blenkernel/BKE_boids.h +++ b/source/blender/blenkernel/BKE_boids.h @@ -23,13 +23,16 @@ * \ingroup bke */ -#include "DNA_boid_types.h" -#include "DNA_particle_types.h" - #ifdef __cplusplus extern "C" { #endif +struct BoidSettings; +struct BoidState; +struct Object; +struct ParticleData; +struct ParticleSettings; +struct ParticleSimulationData; struct RNG; typedef struct BoidBrainData { @@ -50,13 +53,13 @@ typedef struct BoidBrainData { void boids_precalc_rules(struct ParticleSettings *part, float cfra); void boid_brain(BoidBrainData *bbd, int p, struct ParticleData *pa); void boid_body(BoidBrainData *bbd, struct ParticleData *pa); -void boid_default_settings(BoidSettings *boids); -BoidRule *boid_new_rule(int type); -BoidState *boid_new_state(BoidSettings *boids); -BoidState *boid_duplicate_state(BoidSettings *boids, BoidState *state); -void boid_free_settings(BoidSettings *boids); -BoidSettings *boid_copy_settings(const BoidSettings *boids); -BoidState *boid_get_current_state(BoidSettings *boids); +void boid_default_settings(struct BoidSettings *boids); +struct BoidRule *boid_new_rule(int type); +struct BoidState *boid_new_state(struct BoidSettings *boids); +struct BoidState *boid_duplicate_state(struct BoidSettings *boids, struct BoidState *state); +void boid_free_settings(struct BoidSettings *boids); +struct BoidSettings *boid_copy_settings(const struct BoidSettings *boids); +struct BoidState *boid_get_current_state(struct BoidSettings *boids); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_collision.h b/source/blender/blenkernel/BKE_collision.h index 3a5328a33e2..ff1bca896b1 100644 --- a/source/blender/blenkernel/BKE_collision.h +++ b/source/blender/blenkernel/BKE_collision.h @@ -22,21 +22,11 @@ * \ingroup bke */ -#include <float.h> -#include <math.h> -#include <stdlib.h> -#include <string.h> - -/* types */ -#include "BKE_collision.h" -#include "DNA_cloth_types.h" - -#include "BLI_kdopbvh.h" - #ifdef __cplusplus extern "C" { #endif +struct BVHTree; struct Collection; struct CollisionModifierData; struct Depsgraph; @@ -113,11 +103,11 @@ typedef struct FaceCollPair { // used in modifier.c from collision.c ///////////////////////////////////////////////// -BVHTree *bvhtree_build_from_mvert(const struct MVert *mvert, - const struct MVertTri *tri, - int tri_num, - float epsilon); -void bvhtree_update_from_mvert(BVHTree *bvhtree, +struct BVHTree *bvhtree_build_from_mvert(const struct MVert *mvert, + const struct MVertTri *tri, + int tri_num, + float epsilon); +void bvhtree_update_from_mvert(struct BVHTree *bvhtree, const struct MVert *mvert, const struct MVert *mvert_moving, const struct MVertTri *tri, diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h index 1589bff7501..afad1e26159 100644 --- a/source/blender/blenkernel/BKE_constraint.h +++ b/source/blender/blenkernel/BKE_constraint.h @@ -23,6 +23,10 @@ * \ingroup bke */ +struct BlendDataReader; +struct BlendExpander; +struct BlendLibReader; +struct BlendWriter; struct Depsgraph; struct ID; struct ListBase; @@ -31,10 +35,6 @@ struct Scene; struct bConstraint; struct bConstraintTarget; struct bPoseChannel; -struct BlendWriter; -struct BlendDataReader; -struct BlendLibReader; -struct BlendExpander; /* ---------------------------------------------------------------------------- */ #ifdef __cplusplus @@ -177,8 +177,8 @@ struct bConstraint *BKE_constraint_find_from_target(struct Object *ob, struct bConstraintTarget *tgt, struct bPoseChannel **r_pchan); -bool BKE_constraint_is_local_in_liboverride(const struct Object *ob, - const struct bConstraint *con); +bool BKE_constraint_is_nonlocal_in_liboverride(const struct Object *ob, + const struct bConstraint *con); struct bConstraint *BKE_constraint_add_for_object(struct Object *ob, const char *name, short type); struct bConstraint *BKE_constraint_add_for_pose(struct Object *ob, diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h index 5c534803781..94392dd78da 100644 --- a/source/blender/blenkernel/BKE_context.h +++ b/source/blender/blenkernel/BKE_context.h @@ -143,8 +143,9 @@ bContext *CTX_copy(const bContext *C); /* Stored Context */ -bContextStore *CTX_store_add(ListBase *contexts, const char *name, PointerRNA *ptr); +bContextStore *CTX_store_add(ListBase *contexts, const char *name, const PointerRNA *ptr); bContextStore *CTX_store_add_all(ListBase *contexts, bContextStore *context); +bContextStore *CTX_store_get(bContext *C); void CTX_store_set(bContext *C, bContextStore *store); bContextStore *CTX_store_copy(bContextStore *store); void CTX_store_free(bContextStore *store); @@ -288,6 +289,9 @@ enum eContextObjectMode CTX_data_mode_enum(const bContext *C); void CTX_data_main_set(bContext *C, struct Main *bmain); void CTX_data_scene_set(bContext *C, struct Scene *scene); +/* Only Outliner currently! */ +int CTX_data_selected_ids(const bContext *C, ListBase *list); + int CTX_data_selected_editable_objects(const bContext *C, ListBase *list); int CTX_data_selected_editable_bases(const bContext *C, ListBase *list); diff --git a/source/blender/blenkernel/BKE_cryptomatte.h b/source/blender/blenkernel/BKE_cryptomatte.h index 9ad4770c754..433c25084ad 100644 --- a/source/blender/blenkernel/BKE_cryptomatte.h +++ b/source/blender/blenkernel/BKE_cryptomatte.h @@ -29,14 +29,21 @@ extern "C" { #endif -struct Object; +struct Main; struct Material; +struct Object; +uint32_t BKE_cryptomatte_hash(const char *name, int name_len); uint32_t BKE_cryptomatte_object_hash(const struct Object *object); uint32_t BKE_cryptomatte_material_hash(const struct Material *material); uint32_t BKE_cryptomatte_asset_hash(const struct Object *object); float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash); +char *BKE_cryptomatte_entries_to_matte_id(struct NodeCryptomatte *node_storage); +void BKE_cryptomatte_matte_id_to_entries(const struct Main *bmain, + struct NodeCryptomatte *node_storage, + const char *matte_id); + #ifdef __cplusplus } -#endif
\ No newline at end of file +#endif diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h index dcb4a993da1..881b93fe709 100644 --- a/source/blender/blenkernel/BKE_curve.h +++ b/source/blender/blenkernel/BKE_curve.h @@ -22,7 +22,9 @@ * \ingroup bke */ -#include "DNA_scene_types.h" +#include "BLI_sys_types.h" + +#include "DNA_listBase.h" #ifdef __cplusplus extern "C" { @@ -318,8 +320,8 @@ void BKE_curve_deform_coords(const struct Object *ob_curve, const short flag, const short defaxis); -void BKE_curve_deform_coords_with_editmesh(const Object *ob_curve, - const Object *ob_target, +void BKE_curve_deform_coords_with_editmesh(const struct Object *ob_curve, + const struct Object *ob_target, float (*vert_coords)[3], const int vert_coords_len, const int defgrp_index, diff --git a/source/blender/blenkernel/BKE_editmesh.h b/source/blender/blenkernel/BKE_editmesh.h index 0c84ad70845..2fb713a4299 100644 --- a/source/blender/blenkernel/BKE_editmesh.h +++ b/source/blender/blenkernel/BKE_editmesh.h @@ -35,9 +35,7 @@ struct BMLoop; struct BMesh; struct BoundBox; struct Depsgraph; -struct EditMeshData; struct Mesh; -struct MeshStatVis; struct Object; struct Scene; diff --git a/source/blender/blenkernel/BKE_effect.h b/source/blender/blenkernel/BKE_effect.h index 0585f67703c..3cba47afc46 100644 --- a/source/blender/blenkernel/BKE_effect.h +++ b/source/blender/blenkernel/BKE_effect.h @@ -22,8 +22,6 @@ * \ingroup bke */ -#include "DNA_modifier_types.h" - #include "BLI_utildefines.h" #ifdef __cplusplus @@ -147,7 +145,7 @@ float effector_falloff(struct EffectorCache *eff, struct EffectorData *efd, struct EffectedPoint *point, struct EffectorWeights *weights); -int closest_point_on_surface(SurfaceModifierData *surmd, +int closest_point_on_surface(struct SurfaceModifierData *surmd, const float co[3], float surface_co[3], float surface_nor[3], diff --git a/source/blender/blenkernel/BKE_freestyle.h b/source/blender/blenkernel/BKE_freestyle.h index 47f0b547d83..5e29665d728 100644 --- a/source/blender/blenkernel/BKE_freestyle.h +++ b/source/blender/blenkernel/BKE_freestyle.h @@ -23,8 +23,6 @@ * \ingroup bke */ -#include "DNA_scene_types.h" - #ifdef __cplusplus extern "C" { #endif @@ -39,28 +37,31 @@ typedef struct FreestyleModuleSettings FreestyleModuleSettings; typedef struct FreestyleSettings FreestyleSettings; /* FreestyleConfig */ -void BKE_freestyle_config_init(FreestyleConfig *config); -void BKE_freestyle_config_free(FreestyleConfig *config, const bool do_id_user); -void BKE_freestyle_config_copy(FreestyleConfig *new_config, - const FreestyleConfig *config, +void BKE_freestyle_config_init(struct FreestyleConfig *config); +void BKE_freestyle_config_free(struct FreestyleConfig *config, const bool do_id_user); +void BKE_freestyle_config_copy(struct FreestyleConfig *new_config, + const struct FreestyleConfig *config, const int flag); /* FreestyleConfig.modules */ -FreestyleModuleConfig *BKE_freestyle_module_add(FreestyleConfig *config); -bool BKE_freestyle_module_delete(FreestyleConfig *config, FreestyleModuleConfig *module_conf); -bool BKE_freestyle_module_move(FreestyleConfig *config, - FreestyleModuleConfig *module_conf, +struct FreestyleModuleConfig *BKE_freestyle_module_add(struct FreestyleConfig *config); +bool BKE_freestyle_module_delete(struct FreestyleConfig *config, + struct FreestyleModuleConfig *module_conf); +bool BKE_freestyle_module_move(struct FreestyleConfig *config, + struct FreestyleModuleConfig *module_conf, int direction); /* FreestyleConfig.linesets */ -FreestyleLineSet *BKE_freestyle_lineset_add(struct Main *bmain, - FreestyleConfig *config, - const char *name); -bool BKE_freestyle_lineset_delete(FreestyleConfig *config, FreestyleLineSet *lineset); -FreestyleLineSet *BKE_freestyle_lineset_get_active(FreestyleConfig *config); -short BKE_freestyle_lineset_get_active_index(FreestyleConfig *config); -void BKE_freestyle_lineset_set_active_index(FreestyleConfig *config, short index); -void BKE_freestyle_lineset_unique_name(FreestyleConfig *config, FreestyleLineSet *lineset); +struct FreestyleLineSet *BKE_freestyle_lineset_add(struct Main *bmain, + struct FreestyleConfig *config, + const char *name); +bool BKE_freestyle_lineset_delete(struct FreestyleConfig *config, + struct FreestyleLineSet *lineset); +struct FreestyleLineSet *BKE_freestyle_lineset_get_active(struct FreestyleConfig *config); +short BKE_freestyle_lineset_get_active_index(struct FreestyleConfig *config); +void BKE_freestyle_lineset_set_active_index(struct FreestyleConfig *config, short index); +void BKE_freestyle_lineset_unique_name(struct FreestyleConfig *config, + struct FreestyleLineSet *lineset); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_geometry_set.h b/source/blender/blenkernel/BKE_geometry_set.h index 026f4d39d51..37a3ed82bb8 100644 --- a/source/blender/blenkernel/BKE_geometry_set.h +++ b/source/blender/blenkernel/BKE_geometry_set.h @@ -24,18 +24,32 @@ extern "C" { #endif -struct Object; +struct Collection; struct GeometrySet; +struct Object; void BKE_geometry_set_free(struct GeometrySet *geometry_set); bool BKE_geometry_set_has_instances(const struct GeometrySet *geometry_set); +typedef enum InstancedDataType { + INSTANCE_DATA_TYPE_OBJECT = 0, + INSTANCE_DATA_TYPE_COLLECTION = 1, +} InstancedDataType; + +typedef struct InstancedData { + InstancedDataType type; + union { + struct Object *object; + struct Collection *collection; + } data; +} InstancedData; + int BKE_geometry_set_instances(const struct GeometrySet *geometry_set, float (**r_positions)[3], float (**r_rotations)[3], float (**r_scales)[3], - struct Object ***r_objects); + struct InstancedData **r_instanced_data); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh index ef3ae3c381c..e4232a84a00 100644 --- a/source/blender/blenkernel/BKE_geometry_set.hh +++ b/source/blender/blenkernel/BKE_geometry_set.hh @@ -32,9 +32,10 @@ #include "BKE_attribute_access.hh" #include "BKE_geometry_set.h" +struct Collection; struct Mesh; -struct PointCloud; struct Object; +struct PointCloud; /* Each geometry component has a specific type. The type determines what kind of data the component * stores. Functions modifying a geometry will usually just modify a subset of the component types. @@ -88,6 +89,9 @@ class GeometryComponent { GeometryComponentType type() const; + /* Return true when any attribute with this name exists, including built in attributes. */ + bool attribute_exists(const blender::StringRef attribute_name) const; + /* Returns true when the geometry component supports this attribute domain. */ virtual bool attribute_domain_supported(const AttributeDomain domain) const; /* Returns true when the given data type is supported in the given domain. */ @@ -132,6 +136,11 @@ class GeometryComponent { const AttributeDomain domain, const CustomDataType data_type) const; + /* Get a read-only attribute interpolated to the input domain, leaving the data type unchanged. + * Returns null when the attribute does not exist. */ + blender::bke::ReadAttributePtr attribute_try_get_for_read( + const blender::StringRef attribute_name, const AttributeDomain domain) const; + /* Get a read-only attribute for the given domain and data type. * Returns a constant attribute based on the default value if the attribute does not exist. * Never returns null. */ @@ -157,6 +166,14 @@ class GeometryComponent { const CustomDataType data_type, const void *value) const; + /* Create a read-only dummy attribute that always returns the same value. + * The given value is converted to the correct type if necessary. */ + blender::bke::ReadAttributePtr attribute_get_constant_for_read_converted( + const AttributeDomain domain, + const CustomDataType in_data_type, + const CustomDataType out_data_type, + const void *value) const; + /* Get a read-only dummy attribute that always returns the same value. */ template<typename T> blender::bke::TypedReadAttribute<T> attribute_get_constant_for_read(const AttributeDomain domain, @@ -347,7 +364,7 @@ class InstancesComponent : public GeometryComponent { blender::Vector<blender::float3> positions_; blender::Vector<blender::float3> rotations_; blender::Vector<blender::float3> scales_; - blender::Vector<const Object *> objects_; + blender::Vector<InstancedData> instanced_data_; public: InstancesComponent(); @@ -355,12 +372,20 @@ class InstancesComponent : public GeometryComponent { GeometryComponent *copy() const override; void clear(); - void add_instance(const Object *object, + void add_instance(Object *object, blender::float3 position, blender::float3 rotation = {0, 0, 0}, blender::float3 scale = {1, 1, 1}); + void add_instance(Collection *collection, + blender::float3 position, + blender::float3 rotation = {0, 0, 0}, + blender::float3 scale = {1, 1, 1}); + void add_instance(InstancedData data, + blender::float3 position, + blender::float3 rotation, + blender::float3 scale); - blender::Span<const Object *> objects() const; + blender::Span<InstancedData> instanced_data() const; blender::Span<blender::float3> positions() const; blender::Span<blender::float3> rotations() const; blender::Span<blender::float3> scales() const; diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h index 6dc8d1ef06e..df5711f5120 100644 --- a/source/blender/blenkernel/BKE_gpencil.h +++ b/source/blender/blenkernel/BKE_gpencil.h @@ -36,19 +36,17 @@ struct ListBase; struct MDeformVert; struct Main; struct Material; -struct MaterialGPencilStyle; struct Object; struct Scene; struct SpaceImage; struct ToolSettings; struct ViewLayer; struct bDeformGroup; +struct bGPDcurve; struct bGPDframe; struct bGPDlayer; struct bGPDlayer_Mask; -struct bGPDspoint; struct bGPDstroke; -struct bGPDcurve; struct bGPdata; #define GPENCIL_SIMPLIFY(scene) ((scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_ENABLE)) diff --git a/source/blender/blenkernel/BKE_gpencil_curve.h b/source/blender/blenkernel/BKE_gpencil_curve.h index 1821972469c..2d42bb36949 100644 --- a/source/blender/blenkernel/BKE_gpencil_curve.h +++ b/source/blender/blenkernel/BKE_gpencil_curve.h @@ -30,10 +30,10 @@ extern "C" { struct Main; struct Object; struct Scene; -struct bGPdata; +struct bGPDcurve; struct bGPDlayer; struct bGPDstroke; -struct bGPDcurve; +struct bGPdata; void BKE_gpencil_convert_curve(struct Main *bmain, struct Scene *scene, diff --git a/source/blender/blenkernel/BKE_gpencil_geom.h b/source/blender/blenkernel/BKE_gpencil_geom.h index b107a6e72af..1c86df73d3c 100644 --- a/source/blender/blenkernel/BKE_gpencil_geom.h +++ b/source/blender/blenkernel/BKE_gpencil_geom.h @@ -32,12 +32,11 @@ struct Depsgraph; struct Main; struct Object; struct Scene; +struct bGPDcurve; struct bGPDframe; -struct bGPDlayer; struct bGPDspoint; struct bGPDstroke; struct bGPdata; -struct bGPDcurve; /* Object boundbox. */ bool BKE_gpencil_data_minmax(const struct bGPdata *gpd, float r_min[3], float r_max[3]); @@ -164,6 +163,11 @@ bool BKE_gpencil_convert_mesh(struct Main *bmain, const bool use_seams, const bool use_faces); +void BKE_gpencil_stroke_uniform_subdivide(struct bGPdata *gpd, + struct bGPDstroke *gps, + const uint32_t target_number, + const bool select); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_gpencil_modifier.h b/source/blender/blenkernel/BKE_gpencil_modifier.h index bdc583048b8..61ccf3d60f6 100644 --- a/source/blender/blenkernel/BKE_gpencil_modifier.h +++ b/source/blender/blenkernel/BKE_gpencil_modifier.h @@ -27,6 +27,9 @@ extern "C" { #endif struct ARegionType; +struct BlendDataReader; +struct BlendLibReader; +struct BlendWriter; struct Depsgraph; struct GpencilModifierData; struct ID; @@ -35,9 +38,6 @@ struct Main; struct ModifierUpdateDepsgraphContext; struct Object; struct Scene; -struct BlendWriter; -struct BlendDataReader; -struct BlendLibReader; /* NOTE: bakeModifier() called from UI: * needs to create new data-blocks, hence the need for this. */ struct bGPDframe; @@ -278,8 +278,8 @@ void BKE_gpencil_modifiers_foreach_tex_link(struct Object *ob, GreasePencilTexWalkFunc walk, void *userData); -bool BKE_gpencil_modifier_is_local_in_liboverride(const struct Object *ob, - const struct GpencilModifierData *gmd); +bool BKE_gpencil_modifier_is_nonlocal_in_liboverride(const struct Object *ob, + const struct GpencilModifierData *gmd); typedef struct GpencilVirtualModifierData { ArmatureGpencilModifierData amd; diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h index d6cf5eae323..28a6f837f61 100644 --- a/source/blender/blenkernel/BKE_icons.h +++ b/source/blender/blenkernel/BKE_icons.h @@ -23,17 +23,26 @@ * \ingroup bke * * Resizable Icons for Blender + * + * There is some thread safety for this API but it is rather weak. Registering or unregistering + * icons is thread safe, changing data of icons from multiple threads is not. Practically this + * should be fine since only the main thread modifies icons. Should that change, more locks or a + * different design need to be introduced. */ #ifdef __cplusplus extern "C" { #endif +#include "BLI_compiler_attrs.h" + typedef void (*DrawInfoFreeFP)(void *drawinfo); enum { /** ID preview: obj is #ID. */ ICON_DATA_ID = 0, + /** Arbitrary Image buffer: obj is #ImBuf */ + ICON_DATA_IMBUF, /** Preview: obj is #PreviewImage */ ICON_DATA_PREVIEW, /** 2D triangles: obj is #Icon_Geom */ @@ -44,6 +53,9 @@ enum { ICON_DATA_GPLAYER, }; +/** + * \note See comment at the top regarding thread safety. + */ struct Icon { void *drawinfo; /** @@ -93,6 +105,9 @@ int BKE_icon_gplayer_color_ensure(struct bGPDlayer *gpl); int BKE_icon_preview_ensure(struct ID *id, struct PreviewImage *preview); +int BKE_icon_imbuf_create(struct ImBuf *ibuf) ATTR_WARN_UNUSED_RESULT; +struct ImBuf *BKE_icon_imbuf_get_buffer(int icon_id) ATTR_WARN_UNUSED_RESULT; + /* retrieve icon for id */ struct Icon *BKE_icon_get(const int icon_id); @@ -129,6 +144,12 @@ void BKE_previewimg_clear_single(struct PreviewImage *prv, enum eIconSizes size) /* get the preview from any pointer */ struct PreviewImage **BKE_previewimg_id_get_p(const struct ID *id); +struct PreviewImage *BKE_previewimg_id_get(const struct ID *id); + +bool BKE_previewimg_id_supports_jobs(const struct ID *id); + +/* Trigger deferred loading of a custom image file into the preview buffer. */ +void BKE_previewimg_id_custom_set(struct ID *id, const char *path); /* free the preview image belonging to the id */ void BKE_previewimg_id_free(struct ID *id); @@ -146,6 +167,11 @@ struct PreviewImage *BKE_previewimg_id_ensure(struct ID *id); void BKE_previewimg_ensure(struct PreviewImage *prv, const int size); +struct ImBuf *BKE_previewimg_to_imbuf(struct PreviewImage *prv, const int size); + +void BKE_previewimg_finish(struct PreviewImage *prv, const int size); +bool BKE_previewimg_is_finished(const struct PreviewImage *prv, const int size); + struct PreviewImage *BKE_previewimg_cached_get(const char *name); struct PreviewImage *BKE_previewimg_cached_ensure(const char *name); @@ -156,13 +182,14 @@ struct PreviewImage *BKE_previewimg_cached_thumbnail_read(const char *name, bool force_update); void BKE_previewimg_cached_release(const char *name); -void BKE_previewimg_cached_release_pointer(struct PreviewImage *prv); + +void BKE_previewimg_deferred_release(struct PreviewImage *prv); void BKE_previewimg_blend_write(struct BlendWriter *writer, const struct PreviewImage *prv); void BKE_previewimg_blend_read(struct BlendDataReader *reader, struct PreviewImage *prv); int BKE_icon_geom_ensure(struct Icon_Geom *geom); -struct Icon_Geom *BKE_icon_geom_from_memory(const uchar *data, size_t data_len); +struct Icon_Geom *BKE_icon_geom_from_memory(uchar *data, size_t data_len); struct Icon_Geom *BKE_icon_geom_from_file(const char *filename); struct ImBuf *BKE_icon_geom_rasterize(const struct Icon_Geom *geom, diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h index 9c250240e5e..bcf35bf1197 100644 --- a/source/blender/blenkernel/BKE_idprop.h +++ b/source/blender/blenkernel/BKE_idprop.h @@ -20,8 +20,6 @@ * \ingroup bke */ -#include "DNA_ID.h" - #include "BLI_compiler_attrs.h" #ifdef __cplusplus @@ -57,9 +55,9 @@ typedef union IDPropertyTemplate { /* ----------- Property Array Type ---------- */ -IDProperty *IDP_NewIDPArray(const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -IDProperty *IDP_CopyIDPArray(const IDProperty *array, const int flag) ATTR_WARN_UNUSED_RESULT - ATTR_NONNULL(); +struct IDProperty *IDP_NewIDPArray(const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +struct IDProperty *IDP_CopyIDPArray(const struct IDProperty *array, + const int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); /* shallow copies item */ void IDP_SetIndexArray(struct IDProperty *prop, int index, struct IDProperty *item) ATTR_NONNULL(); @@ -74,7 +72,9 @@ void IDP_ResizeArray(struct IDProperty *prop, int newlen); void IDP_FreeArray(struct IDProperty *prop); /* ---------- String Type ------------ */ -IDProperty *IDP_NewString(const char *st, const char *name, int maxlen) ATTR_WARN_UNUSED_RESULT +struct IDProperty *IDP_NewString(const char *st, + const char *name, + int maxlen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2 /* 'name 'arg */); /* maxlen excludes '\0' */ void IDP_AssignString(struct IDProperty *prop, const char *st, int maxlen) ATTR_NONNULL(); /* maxlen excludes '\0' */ @@ -84,9 +84,9 @@ void IDP_FreeString(struct IDProperty *prop) ATTR_NONNULL(); /*-------- ID Type -------*/ -typedef void (*IDPWalkFunc)(void *userData, IDProperty *idp); +typedef void (*IDPWalkFunc)(void *userData, struct IDProperty *idp); -void IDP_AssignID(IDProperty *prop, ID *id, const int flag); +void IDP_AssignID(struct IDProperty *prop, struct ID *id, const int flag); /*-------- Group Functions -------*/ @@ -100,10 +100,10 @@ void IDP_ReplaceInGroup(struct IDProperty *group, struct IDProperty *prop) ATTR_ void IDP_ReplaceInGroup_ex(struct IDProperty *group, struct IDProperty *prop, struct IDProperty *prop_exist); -void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overwrite) +void IDP_MergeGroup(struct IDProperty *dest, const struct IDProperty *src, const bool do_overwrite) ATTR_NONNULL(); -void IDP_MergeGroup_ex(IDProperty *dest, - const IDProperty *src, +void IDP_MergeGroup_ex(struct IDProperty *dest, + const struct IDProperty *src, const bool do_overwrite, const int flag) ATTR_NONNULL(); bool IDP_AddToGroup(struct IDProperty *group, struct IDProperty *prop) ATTR_NONNULL(); @@ -113,11 +113,13 @@ bool IDP_InsertToGroup(struct IDProperty *group, void IDP_RemoveFromGroup(struct IDProperty *group, struct IDProperty *prop) ATTR_NONNULL(); void IDP_FreeFromGroup(struct IDProperty *group, struct IDProperty *prop) ATTR_NONNULL(); -IDProperty *IDP_GetPropertyFromGroup(const struct IDProperty *prop, - const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -IDProperty *IDP_GetPropertyTypeFromGroup(const struct IDProperty *prop, - const char *name, - const char type) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +struct IDProperty *IDP_GetPropertyFromGroup(const struct IDProperty *prop, + const char *name) ATTR_WARN_UNUSED_RESULT + ATTR_NONNULL(); +struct IDProperty *IDP_GetPropertyTypeFromGroup(const struct IDProperty *prop, + const char *name, + const char type) ATTR_WARN_UNUSED_RESULT + ATTR_NONNULL(); /*-------- Main Functions --------*/ struct IDProperty *IDP_GetProperties(struct ID *id, @@ -127,10 +129,10 @@ struct IDProperty *IDP_CopyProperty(const struct IDProperty *prop) ATTR_WARN_UNU ATTR_NONNULL(); struct IDProperty *IDP_CopyProperty_ex(const struct IDProperty *prop, const int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -void IDP_CopyPropertyContent(IDProperty *dst, IDProperty *src) ATTR_NONNULL(); +void IDP_CopyPropertyContent(struct IDProperty *dst, struct IDProperty *src) ATTR_NONNULL(); -bool IDP_EqualsProperties_ex(IDProperty *prop1, - IDProperty *prop2, +bool IDP_EqualsProperties_ex(struct IDProperty *prop1, + struct IDProperty *prop2, const bool is_strict) ATTR_WARN_UNUSED_RESULT; bool IDP_EqualsProperties(struct IDProperty *prop1, @@ -142,12 +144,12 @@ struct IDProperty *IDP_New(const char type, void IDP_FreePropertyContent_ex(struct IDProperty *prop, const bool do_id_user); void IDP_FreePropertyContent(struct IDProperty *prop); -void IDP_FreeProperty_ex(IDProperty *prop, const bool do_id_user); +void IDP_FreeProperty_ex(struct IDProperty *prop, const bool do_id_user); void IDP_FreeProperty(struct IDProperty *prop); -void IDP_ClearProperty(IDProperty *prop); +void IDP_ClearProperty(struct IDProperty *prop); -void IDP_Reset(IDProperty *prop, const IDProperty *reference); +void IDP_Reset(struct IDProperty *prop, const struct IDProperty *reference); #define IDP_Int(prop) ((prop)->data.val) #define IDP_Array(prop) ((prop)->data.pointer) @@ -155,29 +157,29 @@ void IDP_Reset(IDProperty *prop, const IDProperty *reference); #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) # define IDP_Float(prop) \ _Generic((prop), \ - IDProperty *: (*(float *)&(prop)->data.val), \ - const IDProperty *: (*(const float *)&(prop)->data.val)) + struct IDProperty *: (*(float *)&(prop)->data.val), \ + const struct IDProperty *: (*(const float *)&(prop)->data.val)) # define IDP_Double(prop) \ _Generic((prop), \ - IDProperty *: (*(double *)&(prop)->data.val), \ - const IDProperty *: (*(const double *)&(prop)->data.val)) + struct IDProperty *: (*(double *)&(prop)->data.val), \ + const struct IDProperty *: (*(const double *)&(prop)->data.val)) # define IDP_String(prop) \ _Generic((prop), \ - IDProperty *: ((char *) (prop)->data.pointer), \ - const IDProperty *: ((const char *) (prop)->data.pointer)) + struct IDProperty *: ((char *) (prop)->data.pointer), \ + const struct IDProperty *: ((const char *) (prop)->data.pointer)) # define IDP_IDPArray(prop) \ _Generic((prop), \ - IDProperty *: ((IDProperty *) (prop)->data.pointer), \ - const IDProperty *: ((const IDProperty *) (prop)->data.pointer)) + struct IDProperty *: ((struct IDProperty *) (prop)->data.pointer), \ + const struct IDProperty *: ((const struct IDProperty *) (prop)->data.pointer)) # define IDP_Id(prop) \ _Generic((prop), \ - IDProperty *: ((ID *) (prop)->data.pointer), \ - const IDProperty *: ((const ID *) (prop)->data.pointer)) + struct IDProperty *: ((ID *) (prop)->data.pointer), \ + const struct IDProperty *: ((const ID *) (prop)->data.pointer)) #else # define IDP_Float(prop) (*(float *)&(prop)->data.val) # define IDP_Double(prop) (*(double *)&(prop)->data.val) # define IDP_String(prop) ((char *)(prop)->data.pointer) -# define IDP_IDPArray(prop) ((IDProperty *)(prop)->data.pointer) +# define IDP_IDPArray(prop) ((struct IDProperty *)(prop)->data.pointer) # define IDP_Id(prop) ((ID *)(prop)->data.pointer) #endif @@ -185,7 +187,7 @@ void IDP_Reset(IDProperty *prop, const IDProperty *reference); * Call a callback for each idproperty in the hierarchy under given root one (included). * */ -typedef void (*IDPForeachPropertyCallback)(IDProperty *id_property, void *user_data); +typedef void (*IDPForeachPropertyCallback)(struct IDProperty *id_property, void *user_data); void IDP_foreach_property(struct IDProperty *id_property_root, const int type_filter, @@ -194,18 +196,18 @@ void IDP_foreach_property(struct IDProperty *id_property_root, /* Format IDProperty as strings */ char *IDP_reprN(const struct IDProperty *prop, uint *r_len); -void IDP_repr_fn(const IDProperty *prop, +void IDP_repr_fn(const struct IDProperty *prop, void (*str_append_fn)(void *user_data, const char *str, uint str_len), void *user_data); void IDP_print(const struct IDProperty *prop); void IDP_BlendWrite(struct BlendWriter *writer, const struct IDProperty *prop); void IDP_BlendReadData_impl(struct BlendDataReader *reader, - IDProperty **prop, + struct IDProperty **prop, const char *caller_func_id); #define IDP_BlendDataRead(reader, prop) IDP_BlendReadData_impl(reader, prop, __func__) -void IDP_BlendReadLib(struct BlendLibReader *reader, IDProperty *prop); -void IDP_BlendReadExpand(struct BlendExpander *expander, IDProperty *prop); +void IDP_BlendReadLib(struct BlendLibReader *reader, struct IDProperty *prop); +void IDP_BlendReadExpand(struct BlendExpander *expander, struct IDProperty *prop); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index 303945dbf64..c51a5f7e5e1 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -382,6 +382,8 @@ struct GPUTexture *BKE_image_get_gpu_tilemap(struct Image *image, bool BKE_image_has_gpu_texture_premultiplied_alpha(struct Image *image, struct ImBuf *ibuf); void BKE_image_update_gputexture( struct Image *ima, struct ImageUser *iuser, int x, int y, int w, int h); +void BKE_image_update_gputexture_delayed( + struct Image *ima, struct ImBuf *ibuf, int x, int y, int w, int h); void BKE_image_paint_set_mipmap(struct Main *bmain, bool mipmap); /* Delayed free of OpenGL buffers by main thread */ diff --git a/source/blender/blenkernel/BKE_ipo.h b/source/blender/blenkernel/BKE_ipo.h index 40b9f738bfd..f4871c83caf 100644 --- a/source/blender/blenkernel/BKE_ipo.h +++ b/source/blender/blenkernel/BKE_ipo.h @@ -26,7 +26,6 @@ extern "C" { #endif -struct Ipo; struct Main; void do_versions_ipos_to_animato(struct Main *main); diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h index f4c1a6fdcb4..02fa8b306d3 100644 --- a/source/blender/blenkernel/BKE_lattice.h +++ b/source/blender/blenkernel/BKE_lattice.h @@ -38,7 +38,6 @@ struct Main; struct Mesh; struct Object; struct Scene; -struct bGPDstroke; void BKE_lattice_resize(struct Lattice *lt, int u, int v, int w, struct Object *ltOb); struct Lattice *BKE_lattice_add(struct Main *bmain, const char *name); diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h index e5fab35891c..240d6cb18ec 100644 --- a/source/blender/blenkernel/BKE_layer.h +++ b/source/blender/blenkernel/BKE_layer.h @@ -23,7 +23,6 @@ #include "BKE_collection.h" #include "DNA_listBase.h" -#include "DNA_scene_types.h" #ifdef __cplusplus extern "C" { @@ -56,9 +55,9 @@ typedef enum eViewLayerCopyMethod { struct ViewLayer *BKE_view_layer_default_view(const struct Scene *scene); struct ViewLayer *BKE_view_layer_default_render(const struct Scene *scene); struct ViewLayer *BKE_view_layer_find(const struct Scene *scene, const char *layer_name); -struct ViewLayer *BKE_view_layer_add(Scene *scene, +struct ViewLayer *BKE_view_layer_add(struct Scene *scene, const char *name, - ViewLayer *view_layer_source, + struct ViewLayer *view_layer_source, const int type); /* DEPRECATED */ @@ -393,10 +392,11 @@ struct ObjectsInModeParams { void *filter_userdata; }; -Base **BKE_view_layer_array_from_bases_in_mode_params(struct ViewLayer *view_layer, - const struct View3D *v3d, - uint *r_len, - const struct ObjectsInModeParams *params); +struct Base **BKE_view_layer_array_from_bases_in_mode_params( + struct ViewLayer *view_layer, + const struct View3D *v3d, + uint *r_len, + const struct ObjectsInModeParams *params); struct Object **BKE_view_layer_array_from_objects_in_mode_params( struct ViewLayer *view_layer, @@ -452,7 +452,8 @@ void BKE_view_layer_verify_aov(struct RenderEngine *engine, struct Scene *scene, struct ViewLayer *view_layer); bool BKE_view_layer_has_valid_aov(struct ViewLayer *view_layer); -ViewLayer *BKE_view_layer_find_with_aov(struct Scene *scene, struct ViewLayerAOV *view_layer_aov); +struct ViewLayer *BKE_view_layer_find_with_aov(struct Scene *scene, + struct ViewLayerAOV *view_layer_aov); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h index e89ed08b423..f954dd06cc9 100644 --- a/source/blender/blenkernel/BKE_lib_id.h +++ b/source/blender/blenkernel/BKE_lib_id.h @@ -52,7 +52,6 @@ extern "C" { #endif -struct BlendDataReader; struct BlendWriter; struct GHash; struct ID; @@ -299,6 +298,8 @@ void BKE_id_tag_clear_atomic(struct ID *id, int tag); bool BKE_id_is_in_global_main(struct ID *id); +bool BKE_id_can_be_asset(const struct ID *id); + void BKE_id_ordered_list(struct ListBase *ordered_lb, const struct ListBase *lb); void BKE_id_reorder(const struct ListBase *lb, struct ID *id, struct ID *relative, bool after); diff --git a/source/blender/blenkernel/BKE_lib_override.h b/source/blender/blenkernel/BKE_lib_override.h index bf6b5cbccef..13edabd4cb7 100644 --- a/source/blender/blenkernel/BKE_lib_override.h +++ b/source/blender/blenkernel/BKE_lib_override.h @@ -72,6 +72,7 @@ void BKE_lib_override_library_dependencies_tag(struct Main *bmain, void BKE_lib_override_library_override_group_tag(struct Main *bmain, struct ID *id_root, const uint tag, + const uint missing_tag, const bool do_create_main_relashionships); bool BKE_lib_override_library_create(struct Main *bmain, struct Scene *scene, diff --git a/source/blender/blenkernel/BKE_lib_remap.h b/source/blender/blenkernel/BKE_lib_remap.h index fb14e340d8b..a8d75213d39 100644 --- a/source/blender/blenkernel/BKE_lib_remap.h +++ b/source/blender/blenkernel/BKE_lib_remap.h @@ -38,8 +38,6 @@ extern "C" { #endif -struct wmWindowManager; - /* BKE_libblock_free, delete are declared in BKE_lib_id.h for convenience. */ /* Also IDRemap->flag. */ diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 8dc17410979..2482d61777c 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -26,7 +26,6 @@ #include "BLI_utildefines.h" struct BLI_Stack; -struct BMEditMesh; struct BMesh; struct BMeshCreateParams; struct BMeshFromMeshParams; @@ -679,7 +678,7 @@ void BKE_mesh_calc_edges_loose(struct Mesh *mesh); void BKE_mesh_calc_edges(struct Mesh *mesh, bool keep_existing_edges, const bool select_new_edges); void BKE_mesh_calc_edges_tessface(struct Mesh *mesh); -/* In DerivedMesh.c */ +/* In DerivedMesh.cc */ void BKE_mesh_wrapper_deferred_finalize(struct Mesh *me_eval, const CustomData_MeshMasks *cd_mask_finalize); diff --git a/source/blender/blenkernel/BKE_mesh_fair.h b/source/blender/blenkernel/BKE_mesh_fair.h new file mode 100644 index 00000000000..2d5c85d4129 --- /dev/null +++ b/source/blender/blenkernel/BKE_mesh_fair.h @@ -0,0 +1,56 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Mesh Fairing algorithm designed by Brett Fedack, used in the addon "Mesh Fairing": + * https://github.com/fedackb/mesh-fairing. + */ + +#pragma once + +/** \file + * \ingroup bke + */ + +#include "BLI_utildefines.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Mesh Fairing. */ +/* Creates a smooth as possible geometry patch in a defined area. Different values of depth allow + * to minimize changes in the vertex positions or tangency in the affected area. */ + +typedef enum eMeshFairingDepth { + MESH_FAIRING_DEPTH_POSITION = 1, + MESH_FAIRING_DEPTH_TANGENCY = 2, +} eMeshFairingDepth; + +/* affect_vertices is used to define the fairing area. Indexed by vertex index, set to true when + * the vertex should be modified by fairing. */ +void BKE_bmesh_prefair_and_fair_vertices(struct BMesh *bm, + bool *affect_vertices, + const eMeshFairingDepth depth); + +/* This function can optionally use the MVert coordinates of deform_mverts to read and write the + * fairing result. When NULL, the function will use mesh->mverts directly. */ +void BKE_mesh_prefair_and_fair_vertices(struct Mesh *mesh, + struct MVert *deform_mverts, + bool *affect_vertices, + const eMeshFairingDepth depth); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/blenkernel/BKE_mesh_runtime.h b/source/blender/blenkernel/BKE_mesh_runtime.h index 87b55c581a2..67c87e96aff 100644 --- a/source/blender/blenkernel/BKE_mesh_runtime.h +++ b/source/blender/blenkernel/BKE_mesh_runtime.h @@ -57,9 +57,9 @@ void BKE_mesh_runtime_verttri_from_looptri(struct MVertTri *r_verttri, const struct MLoopTri *looptri, int looptri_num); -/* NOTE: the functions below are defined in DerivedMesh.c, and are intended to be moved +/* NOTE: the functions below are defined in DerivedMesh.cc, and are intended to be moved * to a more suitable location when that file is removed. - * They should also be renamed to use conventions from BKE, not old DerivedMesh.c. + * They should also be renamed to use conventions from BKE, not old DerivedMesh.cc. * For now keep the names similar to avoid confusion. */ struct Mesh *mesh_get_eval_final(struct Depsgraph *depsgraph, struct Scene *scene, diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h index 37f566d6f8e..685a8ed98e2 100644 --- a/source/blender/blenkernel/BKE_modifier.h +++ b/source/blender/blenkernel/BKE_modifier.h @@ -35,6 +35,7 @@ struct BlendWriter; struct CustomData_MeshMasks; struct DepsNodeHandle; struct Depsgraph; +struct GeometrySet; struct ID; struct ListBase; struct Main; @@ -43,7 +44,6 @@ struct ModifierData; struct Object; struct Scene; struct bArmature; -struct GeometrySet; typedef enum { /* Should not be used, only for None modifier type */ @@ -244,12 +244,20 @@ typedef struct ModifierTypeInfo { struct Mesh *(*modifyMesh)(struct ModifierData *md, const struct ModifierEvalContext *ctx, struct Mesh *mesh); + struct Hair *(*modifyHair)(struct ModifierData *md, const struct ModifierEvalContext *ctx, struct Hair *hair); - void (*modifyPointCloud)(struct ModifierData *md, - const struct ModifierEvalContext *ctx, - struct GeometrySet *geometry_set); + + /** + * The modifier has to change the geometry set in-place. The geometry set can contain zero or + * more geometry components. This callback can be used by modifiers that don't work on any + * specific type of geometry (e.g. mesh). + */ + void (*modifyGeometrySet)(struct ModifierData *md, + const struct ModifierEvalContext *ctx, + struct GeometrySet *geometry_set); + struct Volume *(*modifyVolume)(struct ModifierData *md, const struct ModifierEvalContext *ctx, struct Volume *volume); @@ -431,7 +439,8 @@ bool BKE_modifier_is_non_geometrical(ModifierData *md); bool BKE_modifier_is_enabled(const struct Scene *scene, struct ModifierData *md, int required_mode); -bool BKE_modifier_is_local_in_liboverride(const struct Object *ob, const struct ModifierData *md); +bool BKE_modifier_is_nonlocal_in_liboverride(const struct Object *ob, + const struct ModifierData *md); void BKE_modifier_set_error(const struct Object *ob, struct ModifierData *md, const char *format, diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h index a6dd69d4322..391d0104be5 100644 --- a/source/blender/blenkernel/BKE_multires.h +++ b/source/blender/blenkernel/BKE_multires.h @@ -23,14 +23,13 @@ * \ingroup bke */ +#include "BKE_subsurf.h" #include "BLI_compiler_compat.h" #ifdef __cplusplus extern "C" { #endif -enum MultiresModifiedFlags; - struct Depsgraph; struct DerivedMesh; struct MDisps; diff --git a/source/blender/blenkernel/BKE_nla.h b/source/blender/blenkernel/BKE_nla.h index 8671324fab1..16d48024d07 100644 --- a/source/blender/blenkernel/BKE_nla.h +++ b/source/blender/blenkernel/BKE_nla.h @@ -60,9 +60,13 @@ struct NlaTrack *BKE_nlatrack_copy(struct Main *bmain, const int flag); void BKE_nla_tracks_copy(struct Main *bmain, ListBase *dst, ListBase *src, const int flag); -struct NlaTrack *BKE_nlatrack_add(struct AnimData *adt, struct NlaTrack *prev); +struct NlaTrack *BKE_nlatrack_add(struct AnimData *adt, + struct NlaTrack *prev, + bool is_liboverride); struct NlaStrip *BKE_nlastrip_new(struct bAction *act); -struct NlaStrip *BKE_nlastack_add_strip(struct AnimData *adt, struct bAction *act); +struct NlaStrip *BKE_nlastack_add_strip(struct AnimData *adt, + struct bAction *act, + const bool is_liboverride); struct NlaStrip *BKE_nla_add_soundstrip(struct Main *bmain, struct Scene *scene, struct Speaker *speaker); @@ -95,10 +99,14 @@ void BKE_nlatrack_solo_toggle(struct AnimData *adt, struct NlaTrack *nlt); bool BKE_nlatrack_has_space(struct NlaTrack *nlt, float start, float end); void BKE_nlatrack_sort_strips(struct NlaTrack *nlt); -bool BKE_nlatrack_add_strip(struct NlaTrack *nlt, struct NlaStrip *strip); +bool BKE_nlatrack_add_strip(struct NlaTrack *nlt, + struct NlaStrip *strip, + const bool is_liboverride); bool BKE_nlatrack_get_bounds(struct NlaTrack *nlt, float bounds[2]); +bool BKE_nlatrack_is_nonlocal_in_liboverride(const struct ID *id, const struct NlaTrack *nlt); + /* ............ */ struct NlaStrip *BKE_nlastrip_find_active(struct NlaTrack *nlt); @@ -124,11 +132,11 @@ void BKE_nla_validate_state(struct AnimData *adt); /* ............ */ bool BKE_nla_action_is_stashed(struct AnimData *adt, struct bAction *act); -bool BKE_nla_action_stash(struct AnimData *adt); +bool BKE_nla_action_stash(struct AnimData *adt, const bool is_liboverride); /* ............ */ -void BKE_nla_action_pushdown(struct AnimData *adt); +void BKE_nla_action_pushdown(struct AnimData *adt, const bool is_liboverride); bool BKE_nla_tweakmode_enter(struct AnimData *adt); void BKE_nla_tweakmode_exit(struct AnimData *adt); diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index a8a94958772..e18f46c9988 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -451,7 +451,7 @@ bool ntreeHasType(const struct bNodeTree *ntree, int type); bool ntreeHasTree(const struct bNodeTree *ntree, const struct bNodeTree *lookup); void ntreeUpdateTree(struct Main *main, struct bNodeTree *ntree); void ntreeUpdateAllNew(struct Main *main); -void ntreeUpdateAllUsers(struct Main *main, struct bNodeTree *ngroup); +void ntreeUpdateAllUsers(struct Main *main, struct ID *id); void ntreeGetDependencyList(struct bNodeTree *ntree, struct bNode ***deplist, int *totnodes); @@ -1204,6 +1204,7 @@ void ntreeGPUMaterialNodes(struct bNodeTree *localtree, #define CMP_NODE_SWITCH_VIEW 322 #define CMP_NODE_CRYPTOMATTE 323 #define CMP_NODE_DENOISE 324 +#define CMP_NODE_EXPOSURE 325 /* channel toggles */ #define CMP_CHAN_RGB 1 @@ -1347,9 +1348,14 @@ int ntreeTexExecTree(struct bNodeTree *ntree, #define GEO_NODE_POINT_INSTANCE 1005 #define GEO_NODE_SUBDIVISION_SURFACE 1006 #define GEO_NODE_OBJECT_INFO 1007 -#define GEO_NODE_RANDOM_ATTRIBUTE 1008 +#define GEO_NODE_ATTRIBUTE_RANDOMIZE 1008 #define GEO_NODE_ATTRIBUTE_MATH 1009 #define GEO_NODE_JOIN_GEOMETRY 1010 +#define GEO_NODE_ATTRIBUTE_FILL 1011 +#define GEO_NODE_ATTRIBUTE_MIX 1012 +#define GEO_NODE_ATTRIBUTE_COLOR_RAMP 1013 +#define GEO_NODE_POINT_SEPARATE 1014 +#define GEO_NODE_ATTRIBUTE_COMPARE 1015 /** \} */ @@ -1364,6 +1370,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree, #define FN_NODE_COMBINE_STRINGS 1204 #define FN_NODE_OBJECT_TRANSFORMS 1205 #define FN_NODE_RANDOM_FLOAT 1206 +#define FN_NODE_INPUT_VECTOR 1207 /** \} */ diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 92f68807fe7..3e4fb793e98 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -25,6 +25,7 @@ #include "BLI_bitmap.h" #include "BLI_utildefines.h" +#include "DNA_brush_enums.h" #include "DNA_object_enums.h" #include "BKE_pbvh.h" @@ -34,6 +35,9 @@ extern "C" { struct BMFace; struct BMesh; +struct BlendDataReader; +struct BlendLibReader; +struct BlendWriter; struct Brush; struct CurveMapping; struct Depsgraph; @@ -55,7 +59,6 @@ struct Paint; struct PaintCurve; struct Palette; struct PaletteColor; -struct ReportList; struct Scene; struct StrokeCache; struct SubdivCCG; @@ -67,11 +70,6 @@ struct ViewLayer; struct bContext; struct bToolRef; struct tPaletteColorHSV; -struct BlendWriter; -struct BlendDataReader; -struct BlendLibReader; - -enum eOverlayFlags; extern const char PAINT_CURSOR_SCULPT[3]; extern const char PAINT_CURSOR_VERTEX_PAINT[3]; diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index 73815325594..3913ede9049 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -29,11 +29,8 @@ #include "BLI_buffer.h" #include "BLI_utildefines.h" -#include "DNA_object_types.h" #include "DNA_particle_types.h" -#include "BKE_customdata.h" - #ifdef __cplusplus extern "C" { #endif @@ -45,9 +42,9 @@ struct ParticleSystemModifierData; struct BVHTreeRay; struct BVHTreeRayHit; -struct BlendWriter; struct BlendDataReader; struct BlendLibReader; +struct BlendWriter; struct CustomData_MeshMasks; struct Depsgraph; struct EdgeHash; @@ -302,7 +299,7 @@ int psys_get_tot_child(struct Scene *scene, struct ParticleSystem *psys_get_current(struct Object *ob); /* for rna */ short psys_get_current_num(struct Object *ob); -void psys_set_current_num(Object *ob, int index); +void psys_set_current_num(struct Object *ob, int index); /* UNUSED */ // struct Object *psys_find_object(struct Scene *scene, struct ParticleSystem *psys); diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index f31f2b59967..9428834f99d 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -70,7 +70,6 @@ struct PBVH; struct PBVHNode; struct SubdivCCG; struct TaskParallelSettings; -struct TaskParallelTLS; typedef struct PBVH PBVH; typedef struct PBVHNode PBVHNode; diff --git a/source/blender/blenkernel/BKE_persistent_data_handle.hh b/source/blender/blenkernel/BKE_persistent_data_handle.hh index 42a853886d7..bbee09c7bf4 100644 --- a/source/blender/blenkernel/BKE_persistent_data_handle.hh +++ b/source/blender/blenkernel/BKE_persistent_data_handle.hh @@ -27,6 +27,7 @@ #include "DNA_ID.h" +struct Collection; struct Object; namespace blender::bke { @@ -82,6 +83,11 @@ class PersistentObjectHandle : public PersistentIDHandle { using PersistentIDHandle::PersistentIDHandle; }; +class PersistentCollectionHandle : public PersistentIDHandle { + friend PersistentDataHandleMap; + using PersistentIDHandle::PersistentIDHandle; +}; + class PersistentDataHandleMap { private: Map<int32_t, ID *> id_by_handle_; @@ -107,6 +113,12 @@ class PersistentDataHandleMap { return PersistentObjectHandle(handle); } + PersistentCollectionHandle lookup(Collection *collection) const + { + const int handle = handle_by_id_.lookup_default((ID *)collection, -1); + return PersistentCollectionHandle(handle); + } + ID *lookup(const PersistentIDHandle &handle) const { ID *id = id_by_handle_.lookup_default(handle.handle_, nullptr); @@ -124,6 +136,18 @@ class PersistentDataHandleMap { } return (Object *)id; } + + Collection *lookup(const PersistentCollectionHandle &handle) const + { + ID *id = this->lookup((const PersistentIDHandle &)handle); + if (id == nullptr) { + return nullptr; + } + if (GS(id->name) != ID_GR) { + return nullptr; + } + return (Collection *)id; + } }; } // namespace blender::bke diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h index f2edebededc..170eb4ba662 100644 --- a/source/blender/blenkernel/BKE_pointcache.h +++ b/source/blender/blenkernel/BKE_pointcache.h @@ -23,12 +23,10 @@ * \ingroup bke */ -#include "DNA_ID.h" -#include "DNA_boid_types.h" -#include "DNA_dynamicpaint_types.h" -#include "DNA_object_force_types.h" -#include "DNA_pointcache_types.h" -#include <stdio.h> /* for FILE */ +#include "DNA_boid_types.h" /* for #BoidData */ +#include "DNA_pointcache_types.h" /* for #BPHYS_TOT_DATA */ + +#include <stdio.h> /* for #FILE */ #ifdef __cplusplus extern "C" { @@ -79,7 +77,10 @@ extern "C" { #define PTCACHE_READ_OLD 3 /* Structs */ +struct BlendDataReader; +struct BlendWriter; struct ClothModifierData; +struct DynamicPaintSurface; struct FluidModifierData; struct ListBase; struct Main; @@ -91,8 +92,6 @@ struct RigidBodyWorld; struct Scene; struct SoftBody; struct ViewLayer; -struct BlendWriter; -struct BlendDataReader; /* temp structure for read/write */ typedef struct PTCacheData { diff --git a/source/blender/blenkernel/BKE_preferences.h b/source/blender/blenkernel/BKE_preferences.h new file mode 100644 index 00000000000..04a41d425bb --- /dev/null +++ b/source/blender/blenkernel/BKE_preferences.h @@ -0,0 +1,56 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#pragma once + +/** \file + * \ingroup bke + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "BLI_compiler_attrs.h" + +struct UserDef; +struct bUserAssetLibrary; + +void BKE_preferences_asset_library_free(struct bUserAssetLibrary *library) ATTR_NONNULL(); + +struct bUserAssetLibrary *BKE_preferences_asset_library_add(struct UserDef *userdef, + const char *name, + const char *path) ATTR_NONNULL(1); +void BKE_preferences_asset_library_name_set(struct UserDef *userdef, + struct bUserAssetLibrary *library, + const char *name) ATTR_NONNULL(); + +void BKE_preferences_asset_library_remove(struct UserDef *userdef, + struct bUserAssetLibrary *library) ATTR_NONNULL(); + +struct bUserAssetLibrary *BKE_preferences_asset_library_find_from_index( + const struct UserDef *userdef, int index) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT; +struct bUserAssetLibrary *BKE_preferences_asset_library_find_from_name( + const struct UserDef *userdef, const char *name) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT; +int BKE_preferences_asset_library_get_index(const struct UserDef *userdef, + const struct bUserAssetLibrary *library) + ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT; + +void BKE_preferences_asset_library_default_add(struct UserDef *userdef) ATTR_NONNULL(); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index 473a684eaba..7b5df98d148 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -51,7 +51,6 @@ struct View3D; struct View3DShading; struct WorkSpace; struct bContext; -struct bContextDataResult; struct bScreen; struct uiLayout; struct uiList; diff --git a/source/blender/blenkernel/BKE_sequencer_offscreen.h b/source/blender/blenkernel/BKE_sequencer_offscreen.h index f5f6067b06e..25a78fcfbad 100644 --- a/source/blender/blenkernel/BKE_sequencer_offscreen.h +++ b/source/blender/blenkernel/BKE_sequencer_offscreen.h @@ -23,26 +23,23 @@ * \ingroup bke */ -#include "DNA_object_enums.h" - -#include "DNA_view3d_types.h" - -#include "IMB_imbuf_types.h" - #ifdef __cplusplus extern "C" { #endif struct GPUOffScreen; +enum eDrawType; +enum eImBufFlags; + typedef struct ImBuf *(*SequencerDrawView)(struct Depsgraph *depsgraph, struct Scene *scene, struct View3DShading *shading_override, - eDrawType drawtype, + enum eDrawType drawtype, struct Object *camera, int width, int height, - eImBufFlags flag, + enum eImBufFlags flag, eV3DOffscreenDrawFlag draw_flags, int alpha_mode, const char *viewname, diff --git a/source/blender/blenkernel/BKE_shader_fx.h b/source/blender/blenkernel/BKE_shader_fx.h index 7c2d363be5c..23bd62c70bc 100644 --- a/source/blender/blenkernel/BKE_shader_fx.h +++ b/source/blender/blenkernel/BKE_shader_fx.h @@ -19,7 +19,6 @@ * \ingroup bke */ -#include "BKE_customdata.h" #include "BLI_compiler_attrs.h" #include "DNA_shader_fx_types.h" /* needed for all enum typdefs */ @@ -28,14 +27,14 @@ extern "C" { #endif struct ARegionType; +struct BlendDataReader; +struct BlendLibReader; +struct BlendWriter; struct ID; struct ListBase; struct ModifierUpdateDepsgraphContext; struct Object; struct ShaderFxData; -struct BlendWriter; -struct BlendDataReader; -struct BlendLibReader; #define SHADER_FX_ACTIVE(_fx, _is_render) \ ((((_fx)->mode & eShaderFxMode_Realtime) && (_is_render == false)) || \ diff --git a/source/blender/blenkernel/BKE_simulation.h b/source/blender/blenkernel/BKE_simulation.h index 23735990079..37372036130 100644 --- a/source/blender/blenkernel/BKE_simulation.h +++ b/source/blender/blenkernel/BKE_simulation.h @@ -16,8 +16,6 @@ #pragma once -#include "DNA_simulation_types.h" - #ifdef __cplusplus extern "C" { #endif @@ -25,6 +23,7 @@ extern "C" { struct Depsgraph; struct Main; struct Scene; +struct Simulation; void *BKE_simulation_add(struct Main *bmain, const char *name); diff --git a/source/blender/blenkernel/BKE_speaker.h b/source/blender/blenkernel/BKE_speaker.h index e288c9f3eb4..9defa887d3c 100644 --- a/source/blender/blenkernel/BKE_speaker.h +++ b/source/blender/blenkernel/BKE_speaker.h @@ -26,7 +26,6 @@ extern "C" { #endif struct Main; -struct Speaker; void *BKE_speaker_add(struct Main *bmain, const char *name); diff --git a/source/blender/blenkernel/BKE_studiolight.h b/source/blender/blenkernel/BKE_studiolight.h index 614523be123..70b8743bcd2 100644 --- a/source/blender/blenkernel/BKE_studiolight.h +++ b/source/blender/blenkernel/BKE_studiolight.h @@ -29,7 +29,7 @@ #include "BLI_path_util.h" -#include "DNA_userdef_types.h" +#include "DNA_userdef_types.h" /* for #SolidLight */ #ifdef __cplusplus extern "C" { diff --git a/source/blender/blenkernel/BKE_text_suggestions.h b/source/blender/blenkernel/BKE_text_suggestions.h index f54e45b6c2f..7561e1d1d08 100644 --- a/source/blender/blenkernel/BKE_text_suggestions.h +++ b/source/blender/blenkernel/BKE_text_suggestions.h @@ -22,8 +22,6 @@ * \ingroup bke */ -#include "DNA_text_types.h" - #ifdef __cplusplus extern "C" { #endif @@ -62,9 +60,9 @@ typedef struct SuggList { void free_texttools(void); /* Used to identify which Text object the current tools should appear against */ -void texttool_text_set_active(Text *text); +void texttool_text_set_active(struct Text *text); void texttool_text_clear(void); -short texttool_text_is_active(Text *text); +short texttool_text_is_active(struct Text *text); /* Suggestions */ void texttool_suggest_add(const char *name, char type); diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index c962f0a6a8c..ae0a180311c 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -36,12 +36,13 @@ set(INC ../makesrna ../modifiers ../nodes + ../render ../sequencer ../shader_fx ../simulation - ../render ../../../intern/ghost ../../../intern/glew-mx + ../../../intern/eigen ../../../intern/guardedalloc ../../../intern/iksolver/extern ../../../intern/atomic @@ -66,7 +67,7 @@ set(SRC intern/CCGSubSurf.c intern/CCGSubSurf_legacy.c intern/CCGSubSurf_util.c - intern/DerivedMesh.c + intern/DerivedMesh.cc intern/action.c intern/addon.c intern/anim_data.c @@ -77,6 +78,7 @@ set(SRC intern/armature.c intern/armature_deform.c intern/armature_update.c + intern/asset.c intern/attribute.c intern/attribute_access.cc intern/autoexec.c @@ -101,7 +103,7 @@ set(SRC intern/constraint.c intern/context.c intern/crazyspace.c - intern/cryptomatte.c + intern/cryptomatte.cc intern/curve.c intern/curve_bevel.c intern/curve_decimate.c @@ -132,7 +134,7 @@ set(SRC intern/gpencil_geom.c intern/gpencil_modifier.c intern/hair.c - intern/icons.c + intern/icons.cc intern/icons_rasterize.c intern/idprop.c intern/idprop_utils.c @@ -169,6 +171,7 @@ set(SRC intern/mesh.c intern/mesh_convert.c intern/mesh_evaluate.c + intern/mesh_fair.cc intern/mesh_iterators.c intern/mesh_mapping.c intern/mesh_merge.c @@ -214,6 +217,7 @@ set(SRC intern/pbvh_bmesh.c intern/pointcache.c intern/pointcloud.cc + intern/preferences.c intern/report.c intern/rigidbody.c intern/scene.c @@ -271,6 +275,7 @@ set(SRC BKE_attribute.h BKE_attribute_access.hh BKE_autoexec.h + BKE_asset.h BKE_blender.h BKE_blender_copybuffer.h BKE_blender_undo.h @@ -350,6 +355,7 @@ set(SRC BKE_mball_tessellate.h BKE_mesh.h BKE_mesh_iterators.h + BKE_mesh_fair.h BKE_mesh_mapping.h BKE_mesh_mirror.h BKE_mesh_remap.h @@ -374,6 +380,7 @@ set(SRC BKE_persistent_data_handle.hh BKE_pointcache.h BKE_pointcloud.h + BKE_preferences.h BKE_report.h BKE_rigidbody.h BKE_scene.h @@ -726,8 +733,8 @@ if(WITH_GTESTS) intern/armature_test.cc intern/fcurve_test.cc intern/lattice_deform_test.cc - intern/tracking_test.cc intern/layer_test.cc + intern/tracking_test.cc ) set(TEST_INC ../editors/include diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.cc index eeff04788f9..b8219dcf7ac 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.cc @@ -21,8 +21,8 @@ * \ingroup bke */ -#include <limits.h> -#include <string.h> +#include <climits> +#include <cstring> #include "MEM_guardedalloc.h" @@ -38,16 +38,19 @@ #include "BLI_array.h" #include "BLI_bitmap.h" #include "BLI_blenlib.h" +#include "BLI_float2.hh" #include "BLI_linklist.h" #include "BLI_math.h" #include "BLI_task.h" #include "BLI_utildefines.h" +#include "BLI_vector.hh" #include "BKE_DerivedMesh.h" #include "BKE_bvhutils.h" #include "BKE_colorband.h" #include "BKE_deform.h" #include "BKE_editmesh.h" +#include "BKE_geometry_set.hh" #include "BKE_key.h" #include "BKE_layer.h" #include "BKE_lib_id.h" @@ -81,7 +84,7 @@ #ifdef USE_MODIFIER_VALIDATE # define ASSERT_IS_VALID_MESH(mesh) \ - (BLI_assert((mesh == NULL) || (BKE_mesh_is_valid(mesh) == true))) + (BLI_assert((mesh == nullptr) || (BKE_mesh_is_valid(mesh) == true))) #else # define ASSERT_IS_VALID_MESH(mesh) #endif @@ -96,10 +99,11 @@ static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final, static MVert *dm_getVertArray(DerivedMesh *dm) { - MVert *mvert = CustomData_get_layer(&dm->vertData, CD_MVERT); + MVert *mvert = (MVert *)CustomData_get_layer(&dm->vertData, CD_MVERT); if (!mvert) { - mvert = CustomData_add_layer(&dm->vertData, CD_MVERT, CD_CALLOC, NULL, dm->getNumVerts(dm)); + mvert = (MVert *)CustomData_add_layer( + &dm->vertData, CD_MVERT, CD_CALLOC, nullptr, dm->getNumVerts(dm)); CustomData_set_layer_flag(&dm->vertData, CD_MVERT, CD_FLAG_TEMPORARY); dm->copyVertArray(dm, mvert); } @@ -109,10 +113,11 @@ static MVert *dm_getVertArray(DerivedMesh *dm) static MEdge *dm_getEdgeArray(DerivedMesh *dm) { - MEdge *medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE); + MEdge *medge = (MEdge *)CustomData_get_layer(&dm->edgeData, CD_MEDGE); if (!medge) { - medge = CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_CALLOC, NULL, dm->getNumEdges(dm)); + medge = (MEdge *)CustomData_add_layer( + &dm->edgeData, CD_MEDGE, CD_CALLOC, nullptr, dm->getNumEdges(dm)); CustomData_set_layer_flag(&dm->edgeData, CD_MEDGE, CD_FLAG_TEMPORARY); dm->copyEdgeArray(dm, medge); } @@ -122,7 +127,7 @@ static MEdge *dm_getEdgeArray(DerivedMesh *dm) static MFace *dm_getTessFaceArray(DerivedMesh *dm) { - MFace *mface = CustomData_get_layer(&dm->faceData, CD_MFACE); + MFace *mface = (MFace *)CustomData_get_layer(&dm->faceData, CD_MFACE); if (!mface) { int numTessFaces = dm->getNumTessFaces(dm); @@ -132,10 +137,11 @@ static MFace *dm_getTessFaceArray(DerivedMesh *dm) * this layer is needed with non-zero size, but currently CD stuff does not check * for requested layer size on creation and just returns layer which was previously * added (sergey) */ - return NULL; + return nullptr; } - mface = CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL, numTessFaces); + mface = (MFace *)CustomData_add_layer( + &dm->faceData, CD_MFACE, CD_CALLOC, nullptr, numTessFaces); CustomData_set_layer_flag(&dm->faceData, CD_MFACE, CD_FLAG_TEMPORARY); dm->copyTessFaceArray(dm, mface); } @@ -145,10 +151,11 @@ static MFace *dm_getTessFaceArray(DerivedMesh *dm) static MLoop *dm_getLoopArray(DerivedMesh *dm) { - MLoop *mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP); + MLoop *mloop = (MLoop *)CustomData_get_layer(&dm->loopData, CD_MLOOP); if (!mloop) { - mloop = CustomData_add_layer(&dm->loopData, CD_MLOOP, CD_CALLOC, NULL, dm->getNumLoops(dm)); + mloop = (MLoop *)CustomData_add_layer( + &dm->loopData, CD_MLOOP, CD_CALLOC, nullptr, dm->getNumLoops(dm)); CustomData_set_layer_flag(&dm->loopData, CD_MLOOP, CD_FLAG_TEMPORARY); dm->copyLoopArray(dm, mloop); } @@ -158,10 +165,11 @@ static MLoop *dm_getLoopArray(DerivedMesh *dm) static MPoly *dm_getPolyArray(DerivedMesh *dm) { - MPoly *mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY); + MPoly *mpoly = (MPoly *)CustomData_get_layer(&dm->polyData, CD_MPOLY); if (!mpoly) { - mpoly = CustomData_add_layer(&dm->polyData, CD_MPOLY, CD_CALLOC, NULL, dm->getNumPolys(dm)); + mpoly = (MPoly *)CustomData_add_layer( + &dm->polyData, CD_MPOLY, CD_CALLOC, nullptr, dm->getNumPolys(dm)); CustomData_set_layer_flag(&dm->polyData, CD_MPOLY, CD_FLAG_TEMPORARY); dm->copyPolyArray(dm, mpoly); } @@ -171,7 +179,8 @@ static MPoly *dm_getPolyArray(DerivedMesh *dm) static MVert *dm_dupVertArray(DerivedMesh *dm) { - MVert *tmp = MEM_malloc_arrayN(dm->getNumVerts(dm), sizeof(*tmp), "dm_dupVertArray tmp"); + MVert *tmp = (MVert *)MEM_malloc_arrayN( + dm->getNumVerts(dm), sizeof(*tmp), "dm_dupVertArray tmp"); if (tmp) { dm->copyVertArray(dm, tmp); @@ -182,7 +191,8 @@ static MVert *dm_dupVertArray(DerivedMesh *dm) static MEdge *dm_dupEdgeArray(DerivedMesh *dm) { - MEdge *tmp = MEM_malloc_arrayN(dm->getNumEdges(dm), sizeof(*tmp), "dm_dupEdgeArray tmp"); + MEdge *tmp = (MEdge *)MEM_malloc_arrayN( + dm->getNumEdges(dm), sizeof(*tmp), "dm_dupEdgeArray tmp"); if (tmp) { dm->copyEdgeArray(dm, tmp); @@ -193,7 +203,8 @@ static MEdge *dm_dupEdgeArray(DerivedMesh *dm) static MFace *dm_dupFaceArray(DerivedMesh *dm) { - MFace *tmp = MEM_malloc_arrayN(dm->getNumTessFaces(dm), sizeof(*tmp), "dm_dupFaceArray tmp"); + MFace *tmp = (MFace *)MEM_malloc_arrayN( + dm->getNumTessFaces(dm), sizeof(*tmp), "dm_dupFaceArray tmp"); if (tmp) { dm->copyTessFaceArray(dm, tmp); @@ -204,7 +215,8 @@ static MFace *dm_dupFaceArray(DerivedMesh *dm) static MLoop *dm_dupLoopArray(DerivedMesh *dm) { - MLoop *tmp = MEM_malloc_arrayN(dm->getNumLoops(dm), sizeof(*tmp), "dm_dupLoopArray tmp"); + MLoop *tmp = (MLoop *)MEM_malloc_arrayN( + dm->getNumLoops(dm), sizeof(*tmp), "dm_dupLoopArray tmp"); if (tmp) { dm->copyLoopArray(dm, tmp); @@ -215,7 +227,8 @@ static MLoop *dm_dupLoopArray(DerivedMesh *dm) static MPoly *dm_dupPolyArray(DerivedMesh *dm) { - MPoly *tmp = MEM_malloc_arrayN(dm->getNumPolys(dm), sizeof(*tmp), "dm_dupPolyArray tmp"); + MPoly *tmp = (MPoly *)MEM_malloc_arrayN( + dm->getNumPolys(dm), sizeof(*tmp), "dm_dupPolyArray tmp"); if (tmp) { dm->copyPolyArray(dm, tmp); @@ -239,14 +252,14 @@ static const MLoopTri *dm_getLoopTriArray(DerivedMesh *dm) looptri = dm->looptris.array; BLI_rw_mutex_unlock(&loops_cache_lock); - if (looptri != NULL) { + if (looptri != nullptr) { BLI_assert(dm->getNumLoopTri(dm) == dm->looptris.num); } else { BLI_rw_mutex_lock(&loops_cache_lock, THREAD_LOCK_WRITE); - /* We need to ensure array is still NULL inside mutex-protected code, + /* We need to ensure array is still nullptr inside mutex-protected code, * some other thread might have already recomputed those looptris. */ - if (dm->looptris.array == NULL) { + if (dm->looptris.array == nullptr) { dm->recalcLoopTri(dm); } looptri = dm->looptris.array; @@ -343,7 +356,7 @@ void DM_init(DerivedMesh *dm, DM_init_funcs(dm); dm->needsFree = 1; - dm->dirty = 0; + dm->dirty = (DMDirtyFlag)0; /* don't use CustomData_reset(...); because we dont want to touch customdata */ copy_vn_i(dm->vertData.typemap, CD_NUMTYPES, -1); @@ -385,7 +398,7 @@ void DM_from_template_ex(DerivedMesh *dm, DM_init_funcs(dm); dm->needsFree = 1; - dm->dirty = 0; + dm->dirty = (DMDirtyFlag)0; } void DM_from_template(DerivedMesh *dm, DerivedMesh *source, @@ -482,7 +495,7 @@ void DM_ensure_looptri_data(DerivedMesh *dm) const unsigned int totloop = dm->numLoopData; const int looptris_num = poly_to_tri_count(totpoly, totloop); - BLI_assert(dm->looptris.array_wip == NULL); + BLI_assert(dm->looptris.array_wip == nullptr); SWAP(MLoopTri *, dm->looptris.array, dm->looptris.array_wip); @@ -494,8 +507,8 @@ void DM_ensure_looptri_data(DerivedMesh *dm) } if (totpoly) { - if (dm->looptris.array_wip == NULL) { - dm->looptris.array_wip = MEM_malloc_arrayN( + if (dm->looptris.array_wip == nullptr) { + dm->looptris.array_wip = (MLoopTri *)MEM_malloc_arrayN( looptris_num, sizeof(*dm->looptris.array_wip), __func__); dm->looptris.num_alloc = looptris_num; } @@ -656,7 +669,7 @@ void DM_interp_vert_data(DerivedMesh *source, int dest_index) { CustomData_interp( - &source->vertData, &dest->vertData, src_indices, weights, NULL, count, dest_index); + &source->vertData, &dest->vertData, src_indices, weights, nullptr, count, dest_index); } static float (*get_editbmesh_orco_verts(BMEditMesh *em))[3] @@ -669,7 +682,7 @@ static float (*get_editbmesh_orco_verts(BMEditMesh *em))[3] /* these may not really be the orco's, but it's only for preview. * could be solver better once, but isn't simple */ - orco = MEM_malloc_arrayN(em->bm->totvert, sizeof(float[3]), "BMEditMesh Orco"); + orco = (float(*)[3])MEM_malloc_arrayN(em->bm->totvert, sizeof(float[3]), "BMEditMesh Orco"); BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) { copy_v3_v3(orco[i], eve->co); @@ -702,14 +715,14 @@ static float (*get_orco_coords(Object *ob, BMEditMesh *em, int layer, int *free) clmd->sim_parms->shapekey_rest); if (kb && kb->data) { - return kb->data; + return (float(*)[3])kb->data; } } - return NULL; + return nullptr; } - return NULL; + return nullptr; } static Mesh *create_orco_mesh(Object *ob, Mesh *me, BMEditMesh *em, int layer) @@ -719,7 +732,7 @@ static Mesh *create_orco_mesh(Object *ob, Mesh *me, BMEditMesh *em, int layer) int free; if (em) { - mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL, me); + mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, nullptr, me); } else { mesh = BKE_mesh_copy_for_eval(me, true); @@ -748,10 +761,10 @@ static void add_orco_mesh(Object *ob, BMEditMesh *em, Mesh *mesh, Mesh *mesh_orc free = 1; if (mesh_orco->totvert == totvert) { - orco = BKE_mesh_vert_coords_alloc(mesh_orco, NULL); + orco = BKE_mesh_vert_coords_alloc(mesh_orco, nullptr); } else { - orco = BKE_mesh_vert_coords_alloc(mesh, NULL); + orco = BKE_mesh_vert_coords_alloc(mesh, nullptr); } } else { @@ -762,14 +775,14 @@ static void add_orco_mesh(Object *ob, BMEditMesh *em, Mesh *mesh, Mesh *mesh_orc if (orco) { if (layer == CD_ORCO) { - BKE_mesh_orco_verts_transform(ob->data, orco, totvert, 0); + BKE_mesh_orco_verts_transform((Mesh *)ob->data, orco, totvert, 0); } - if (!(layerorco = CustomData_get_layer(&mesh->vdata, layer))) { - CustomData_add_layer(&mesh->vdata, layer, CD_CALLOC, NULL, mesh->totvert); + if (!(layerorco = (float(*)[3])CustomData_get_layer(&mesh->vdata, layer))) { + CustomData_add_layer(&mesh->vdata, layer, CD_CALLOC, nullptr, mesh->totvert); BKE_mesh_update_customdata_pointers(mesh, false); - layerorco = CustomData_get_layer(&mesh->vdata, layer); + layerorco = (float(*)[3])CustomData_get_layer(&mesh->vdata, layer); } memcpy(layerorco, orco, sizeof(float[3]) * totvert); @@ -797,10 +810,10 @@ static void mesh_calc_modifier_final_normals(const Mesh *mesh_input, * (BKE_mesh_calc_normals_split() assumes that if that data exists, it is always valid). */ if (do_poly_normals) { if (!CustomData_has_layer(&mesh_final->pdata, CD_NORMAL)) { - float(*polynors)[3] = CustomData_add_layer( - &mesh_final->pdata, CD_NORMAL, CD_CALLOC, NULL, mesh_final->totpoly); + float(*polynors)[3] = (float(*)[3])CustomData_add_layer( + &mesh_final->pdata, CD_NORMAL, CD_CALLOC, nullptr, mesh_final->totpoly); BKE_mesh_calc_normals_poly(mesh_final->mvert, - NULL, + nullptr, mesh_final->totvert, mesh_final->mloop, mesh_final->mpoly, @@ -869,6 +882,56 @@ void BKE_mesh_wrapper_deferred_finalize(Mesh *me_eval, BLI_assert(me_eval->runtime.wrapper_type_finalize == 0); } +/** + * Modifies the given mesh and geometry set. The geometry set is expect to have NO mesh component. + * After this function ends, the geometry set will still have NO mesh component. Instead, an input + * mesh is passed separately and is returned separately. + * + * The purpose of the geometry set is to store all non-mesh geometry components that are generated + * by modifiers. + */ +static Mesh *modifier_modify_mesh_and_geometry_set(ModifierData *md, + const ModifierEvalContext &mectx, + Object *ob, + Mesh *input_mesh, + GeometrySet &geometry_set) +{ + Mesh *mesh_output = nullptr; + const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type); + if (mti->modifyGeometrySet == nullptr) { + mesh_output = BKE_modifier_modify_mesh(md, &mectx, input_mesh); + } + else { + /* For performance reasons, this should be called by the modifier and/or nodes themselves at + * some point. */ + BKE_mesh_wrapper_ensure_mdata(input_mesh); + + /* Adds a new mesh component to the geometry set based on the #input_mesh. */ + BLI_assert(!geometry_set.has<MeshComponent>()); + MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>(); + mesh_component.replace(input_mesh, GeometryOwnershipType::Editable); + mesh_component.copy_vertex_group_names_from_object(*ob); + + /* Let the modifier change the geometry set. */ + mti->modifyGeometrySet(md, &mectx, &geometry_set); + + /* Release the mesh from the geometry set again. */ + if (geometry_set.has<MeshComponent>()) { + MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>(); + mesh_output = mesh_component.release(); + geometry_set.remove<MeshComponent>(); + } + + /* Return an empty mesh instead of null. */ + if (mesh_output == nullptr) { + mesh_output = BKE_mesh_new_nomain(0, 0, 0, 0, 0); + BKE_mesh_copy_settings(mesh_output, input_mesh); + } + } + + return mesh_output; +} + static void mesh_calc_modifiers(struct Depsgraph *depsgraph, Scene *scene, Object *ob, @@ -880,45 +943,50 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, const bool allow_shared_mesh, /* return args */ Mesh **r_deform, - Mesh **r_final) + Mesh **r_final, + GeometrySet **r_geometry_set) { /* Input and final mesh. Final mesh is only created the moment the first * constructive modifier is executed, or a deform modifier needs normals * or certain data layers. */ - Mesh *mesh_input = ob->data; - Mesh *mesh_final = NULL; - Mesh *mesh_deform = NULL; + Mesh *mesh_input = (Mesh *)ob->data; + Mesh *mesh_final = nullptr; + Mesh *mesh_deform = nullptr; + /* This geometry set contains the non-mesh data that might be generated by modifiers. */ + GeometrySet geometry_set_final; BLI_assert((mesh_input->id.tag & LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT) == 0); /* Deformed vertex locations array. Deform only modifier need this type of * float array rather than MVert*. Tracked along with mesh_final as an * optimization to avoid copying coordinates back and forth if there are * multiple sequential deform only modifiers. */ - float(*deformed_verts)[3] = NULL; + float(*deformed_verts)[3] = nullptr; int num_deformed_verts = mesh_input->totvert; bool isPrevDeform = false; /* Mesh with constructive modifiers but no deformation applied. Tracked * along with final mesh if undeformed / orco coordinates are requested * for texturing. */ - Mesh *mesh_orco = NULL; - Mesh *mesh_orco_cloth = NULL; + Mesh *mesh_orco = nullptr; + Mesh *mesh_orco_cloth = nullptr; /* Modifier evaluation modes. */ const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime; /* Sculpt can skip certain modifiers. */ - const bool has_multires = BKE_sculpt_multires_active(scene, ob) != NULL; + const bool has_multires = BKE_sculpt_multires_active(scene, ob) != nullptr; bool multires_applied = false; const bool sculpt_mode = ob->mode & OB_MODE_SCULPT && ob->sculpt && !use_render; const bool sculpt_dyntopo = (sculpt_mode && ob->sculpt->bm) && !use_render; /* Modifier evaluation contexts for different types of modifiers. */ - ModifierApplyFlag apply_render = use_render ? MOD_APPLY_RENDER : 0; - ModifierApplyFlag apply_cache = use_cache ? MOD_APPLY_USECACHE : 0; - const ModifierEvalContext mectx = {depsgraph, ob, apply_render | apply_cache}; - const ModifierEvalContext mectx_orco = {depsgraph, ob, apply_render | MOD_APPLY_ORCO}; + ModifierApplyFlag apply_render = use_render ? MOD_APPLY_RENDER : (ModifierApplyFlag)0; + ModifierApplyFlag apply_cache = use_cache ? MOD_APPLY_USECACHE : (ModifierApplyFlag)0; + const ModifierEvalContext mectx = { + depsgraph, ob, (ModifierApplyFlag)(apply_render | apply_cache)}; + const ModifierEvalContext mectx_orco = { + depsgraph, ob, (ModifierApplyFlag)(apply_render | MOD_APPLY_ORCO)}; /* Get effective list of modifiers to execute. Some effects like shape keys * are added as virtual modifiers before the user created modifiers. */ @@ -930,10 +998,10 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, * even if the resulting data is not used in a material. Only in object mode. * TODO: this is broken, not drawn by the drawn manager. */ const bool do_mod_mcol = (ob->mode == OB_MODE_OBJECT); - ModifierData *previewmd = NULL; + ModifierData *previewmd = nullptr; CustomData_MeshMasks previewmask = {0}; if (do_mod_mcol) { - /* Find the last active modifier generating a preview, or NULL if none. */ + /* Find the last active modifier generating a preview, or nullptr if none. */ /* XXX Currently, DPaint modifier just ignores this. * Needs a stupid hack... * The whole "modifier preview" thing has to be (re?)designed, anyway! */ @@ -957,7 +1025,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, /* Apply all leading deform modifiers. */ if (useDeform) { for (; md; md = md->next, md_datamask = md_datamask->next) { - const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type); if (!BKE_modifier_is_enabled(scene, md, required_mode)) { continue; @@ -972,7 +1040,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, deformed_verts = BKE_mesh_vert_coords_alloc(mesh_input, &num_deformed_verts); } else if (isPrevDeform && mti->dependsOnNormals && mti->dependsOnNormals(md)) { - if (mesh_final == NULL) { + if (mesh_final == nullptr) { mesh_final = BKE_mesh_copy_for_eval(mesh_input, true); ASSERT_IS_VALID_MESH(mesh_final); } @@ -989,7 +1057,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, /* grab modifiers until index i */ if ((index != -1) && (BLI_findindex(&ob->modifiers, md) >= index)) { - md = NULL; + md = nullptr; break; } } @@ -1009,7 +1077,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, /* Apply all remaining constructive and deforming modifiers. */ bool have_non_onlydeform_modifiers_appled = false; for (; md; md = md->next, md_datamask = md_datamask->next) { - const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type); if (!BKE_modifier_is_enabled(scene, md, required_mode)) { continue; @@ -1069,7 +1137,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, CustomData_MeshMasks mask = {0}; mti->requiredDataMask(ob, md, &mask); if (mask.vmask & CD_MASK_ORCO) { - add_orco_mesh(ob, NULL, mesh_final, mesh_orco, CD_ORCO); + add_orco_mesh(ob, nullptr, mesh_final, mesh_orco, CD_ORCO); } } @@ -1092,7 +1160,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, /* if this is not the last modifier in the stack then recalculate the normals * to avoid giving bogus normals to the next modifier see: T23673. */ else if (isPrevDeform && mti->dependsOnNormals && mti->dependsOnNormals(md)) { - if (mesh_final == NULL) { + if (mesh_final == nullptr) { mesh_final = BKE_mesh_copy_for_eval(mesh_input, true); ASSERT_IS_VALID_MESH(mesh_final); } @@ -1103,7 +1171,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, else { bool check_for_needs_mapping = false; /* apply vertex coordinates or build a Mesh as necessary */ - if (mesh_final != NULL) { + if (mesh_final != nullptr) { if (have_non_onlydeform_modifiers_appled == false) { /* If we only deformed, we won't have initialized #CD_ORIGINDEX. * as this is the only part of the function that initializes mapping. */ @@ -1137,20 +1205,23 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, ((nextmask.vmask | nextmask.emask | nextmask.pmask) & CD_MASK_ORIGINDEX)) { /* calc */ CustomData_add_layer( - &mesh_final->vdata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh_final->totvert); + &mesh_final->vdata, CD_ORIGINDEX, CD_CALLOC, nullptr, mesh_final->totvert); CustomData_add_layer( - &mesh_final->edata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh_final->totedge); + &mesh_final->edata, CD_ORIGINDEX, CD_CALLOC, nullptr, mesh_final->totedge); CustomData_add_layer( - &mesh_final->pdata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh_final->totpoly); + &mesh_final->pdata, CD_ORIGINDEX, CD_CALLOC, nullptr, mesh_final->totpoly); /* Not worth parallelizing this, * gives less than 0.1% overall speedup in best of best cases... */ - range_vn_i( - CustomData_get_layer(&mesh_final->vdata, CD_ORIGINDEX), mesh_final->totvert, 0); - range_vn_i( - CustomData_get_layer(&mesh_final->edata, CD_ORIGINDEX), mesh_final->totedge, 0); - range_vn_i( - CustomData_get_layer(&mesh_final->pdata, CD_ORIGINDEX), mesh_final->totpoly, 0); + range_vn_i((int *)CustomData_get_layer(&mesh_final->vdata, CD_ORIGINDEX), + mesh_final->totvert, + 0); + range_vn_i((int *)CustomData_get_layer(&mesh_final->edata, CD_ORIGINDEX), + mesh_final->totedge, + 0); + range_vn_i((int *)CustomData_get_layer(&mesh_final->pdata, CD_ORIGINDEX), + mesh_final->totpoly, + 0); } } @@ -1168,49 +1239,50 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, /* add cloth rest shape key if needed */ if (mask.vmask & CD_MASK_CLOTH_ORCO) { - add_orco_mesh(ob, NULL, mesh_final, mesh_orco, CD_CLOTH_ORCO); + add_orco_mesh(ob, nullptr, mesh_final, mesh_orco, CD_CLOTH_ORCO); } /* add an origspace layer if needed */ if ((md_datamask->mask.lmask) & CD_MASK_ORIGSPACE_MLOOP) { if (!CustomData_has_layer(&mesh_final->ldata, CD_ORIGSPACE_MLOOP)) { CustomData_add_layer( - &mesh_final->ldata, CD_ORIGSPACE_MLOOP, CD_CALLOC, NULL, mesh_final->totloop); + &mesh_final->ldata, CD_ORIGSPACE_MLOOP, CD_CALLOC, nullptr, mesh_final->totloop); mesh_init_origspace(mesh_final); } } - Mesh *mesh_next = BKE_modifier_modify_mesh(md, &mectx, mesh_final); + Mesh *mesh_next = modifier_modify_mesh_and_geometry_set( + md, mectx, ob, mesh_final, geometry_set_final); ASSERT_IS_VALID_MESH(mesh_next); if (mesh_next) { /* if the modifier returned a new mesh, release the old one */ if (mesh_final != mesh_next) { BLI_assert(mesh_final != mesh_input); - BKE_id_free(NULL, mesh_final); + BKE_id_free(nullptr, mesh_final); } mesh_final = mesh_next; if (deformed_verts) { MEM_freeN(deformed_verts); - deformed_verts = NULL; + deformed_verts = nullptr; } } /* create an orco mesh in parallel */ if (nextmask.vmask & CD_MASK_ORCO) { if (!mesh_orco) { - mesh_orco = create_orco_mesh(ob, mesh_input, NULL, CD_ORCO); + mesh_orco = create_orco_mesh(ob, mesh_input, nullptr, CD_ORCO); } nextmask.vmask &= ~CD_MASK_ORCO; - CustomData_MeshMasks temp_cddata_masks = { - .vmask = CD_MASK_ORIGINDEX, - .emask = CD_MASK_ORIGINDEX, - .fmask = CD_MASK_ORIGINDEX, - .pmask = CD_MASK_ORIGINDEX, - }; - if (mti->requiredDataMask != NULL) { + CustomData_MeshMasks temp_cddata_masks = {0}; + temp_cddata_masks.vmask = CD_MASK_ORIGINDEX; + temp_cddata_masks.emask = CD_MASK_ORIGINDEX; + temp_cddata_masks.fmask = CD_MASK_ORIGINDEX; + temp_cddata_masks.pmask = CD_MASK_ORIGINDEX; + + if (mti->requiredDataMask != nullptr) { mti->requiredDataMask(ob, md, &temp_cddata_masks); } CustomData_MeshMasks_update(&temp_cddata_masks, &nextmask); @@ -1223,7 +1295,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, /* if the modifier returned a new mesh, release the old one */ if (mesh_orco != mesh_next) { BLI_assert(mesh_orco != mesh_input); - BKE_id_free(NULL, mesh_orco); + BKE_id_free(nullptr, mesh_orco); } mesh_orco = mesh_next; @@ -1233,7 +1305,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, /* create cloth orco mesh in parallel */ if (nextmask.vmask & CD_MASK_CLOTH_ORCO) { if (!mesh_orco_cloth) { - mesh_orco_cloth = create_orco_mesh(ob, mesh_input, NULL, CD_CLOTH_ORCO); + mesh_orco_cloth = create_orco_mesh(ob, mesh_input, nullptr, CD_CLOTH_ORCO); } nextmask.vmask &= ~CD_MASK_CLOTH_ORCO; @@ -1249,7 +1321,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, /* if the modifier returned a new mesh, release the old one */ if (mesh_orco_cloth != mesh_next) { BLI_assert(mesh_orco != mesh_input); - BKE_id_free(NULL, mesh_orco_cloth); + BKE_id_free(nullptr, mesh_orco_cloth); } mesh_orco_cloth = mesh_next; @@ -1277,7 +1349,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, } } - BLI_linklist_free((LinkNode *)datamasks, NULL); + BLI_linklist_free((LinkNode *)datamasks, nullptr); for (md = firstmd; md; md = md->next) { BKE_modifier_free_temporary_data(md); @@ -1286,11 +1358,11 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, /* Yay, we are done. If we have a Mesh and deformed vertices, * we need to apply these back onto the Mesh. If we have no * Mesh then we need to build one. */ - if (mesh_final == NULL) { + if (mesh_final == nullptr) { /* Note: this check on cdmask is a bit dodgy, it handles the issue at stake here (see T68211), * but other cases might require similar handling? * Could be a good idea to define a proper CustomData_MeshMask for that then. */ - if (deformed_verts == NULL && allow_shared_mesh && + if (deformed_verts == nullptr && allow_shared_mesh && (final_datamask.lmask & CD_MASK_NORMAL) == 0 && (final_datamask.pmask & CD_MASK_NORMAL) == 0) { mesh_final = mesh_input; @@ -1302,7 +1374,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, if (deformed_verts) { BKE_mesh_vert_coords_apply(mesh_final, deformed_verts); MEM_freeN(deformed_verts); - deformed_verts = NULL; + deformed_verts = nullptr; } /* Denotes whether the object which the modifier stack came from owns the mesh or whether the @@ -1314,19 +1386,19 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, /* No need in ORCO layer if the mesh was not deformed or modified: undeformed mesh in this case * matches input mesh. */ if (is_own_mesh) { - add_orco_mesh(ob, NULL, mesh_final, mesh_orco, CD_ORCO); + add_orco_mesh(ob, nullptr, mesh_final, mesh_orco, CD_ORCO); } if (mesh_deform) { - add_orco_mesh(ob, NULL, mesh_deform, NULL, CD_ORCO); + add_orco_mesh(ob, nullptr, mesh_deform, nullptr, CD_ORCO); } } if (mesh_orco) { - BKE_id_free(NULL, mesh_orco); + BKE_id_free(nullptr, mesh_orco); } if (mesh_orco_cloth) { - BKE_id_free(NULL, mesh_orco_cloth); + BKE_id_free(nullptr, mesh_orco_cloth); } /* Compute normals. */ @@ -1335,16 +1407,16 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, } else { Mesh_Runtime *runtime = &mesh_input->runtime; - if (runtime->mesh_eval == NULL) { - BLI_assert(runtime->eval_mutex != NULL); - BLI_mutex_lock(runtime->eval_mutex); - if (runtime->mesh_eval == NULL) { + if (runtime->mesh_eval == nullptr) { + BLI_assert(runtime->eval_mutex != nullptr); + BLI_mutex_lock((ThreadMutex *)runtime->eval_mutex); + if (runtime->mesh_eval == nullptr) { mesh_final = BKE_mesh_copy_for_eval(mesh_input, true); mesh_calc_modifier_final_normals(mesh_input, &final_datamask, sculpt_dyntopo, mesh_final); mesh_calc_finalize(mesh_input, mesh_final); runtime->mesh_eval = mesh_final; } - BLI_mutex_unlock(runtime->eval_mutex); + BLI_mutex_unlock((ThreadMutex *)runtime->eval_mutex); } mesh_final = runtime->mesh_eval; } @@ -1358,6 +1430,9 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, if (r_deform) { *r_deform = mesh_deform; } + if (r_geometry_set) { + *r_geometry_set = new GeometrySet(std::move(geometry_set_final)); + } } float (*editbmesh_vert_coords_alloc(BMEditMesh *em, int *r_vert_len))[3] @@ -1369,7 +1444,7 @@ float (*editbmesh_vert_coords_alloc(BMEditMesh *em, int *r_vert_len))[3] *r_vert_len = em->bm->totvert; - cos = MEM_malloc_arrayN(em->bm->totvert, sizeof(float[3]), "vertexcos"); + cos = (float(*)[3])MEM_malloc_arrayN(em->bm->totvert, sizeof(float[3]), "vertexcos"); BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) { copy_v3_v3(cos[i], eve->co); @@ -1383,7 +1458,7 @@ bool editbmesh_modifier_is_enabled(Scene *scene, ModifierData *md, bool has_prev_mesh) { - const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type); const int required_mode = eModifierMode_Realtime | eModifierMode_Editmode; if (!BKE_modifier_is_enabled(scene, md, required_mode)) { @@ -1417,10 +1492,10 @@ static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final, * (BKE_mesh_calc_normals_split() assumes that if that data exists, it is always valid). */ if (do_poly_normals) { if (!CustomData_has_layer(&mesh_final->pdata, CD_NORMAL)) { - float(*polynors)[3] = CustomData_add_layer( - &mesh_final->pdata, CD_NORMAL, CD_CALLOC, NULL, mesh_final->totpoly); + float(*polynors)[3] = (float(*)[3])CustomData_add_layer( + &mesh_final->pdata, CD_NORMAL, CD_CALLOC, nullptr, mesh_final->totpoly); BKE_mesh_calc_normals_poly(mesh_final->mvert, - NULL, + nullptr, mesh_final->totvert, mesh_final->mloop, mesh_final->mpoly, @@ -1442,7 +1517,7 @@ static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final, * check if the derived meshes are DM_TYPE_EDITBMESH before calling, this isn't essential * but quiets annoying error messages since tessfaces wont be created. */ if (final_datamask->fmask & CD_MASK_MFACE) { - if (mesh_final->edit_mesh == NULL) { + if (mesh_final->edit_mesh == nullptr) { BKE_mesh_tessface_ensure(mesh_final); } } @@ -1466,35 +1541,39 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, const CustomData_MeshMasks *dataMask, /* return args */ Mesh **r_cage, - Mesh **r_final) + Mesh **r_final, + GeometrySet **r_geometry_set) { /* Input and final mesh. Final mesh is only created the moment the first * constructive modifier is executed, or a deform modifier needs normals * or certain data layers. */ - Mesh *mesh_input = ob->data; - Mesh *mesh_final = NULL; - Mesh *mesh_cage = NULL; + Mesh *mesh_input = (Mesh *)ob->data; + Mesh *mesh_final = nullptr; + Mesh *mesh_cage = nullptr; + /* This geometry set contains the non-mesh data that might be generated by modifiers. */ + GeometrySet geometry_set_final; /* Deformed vertex locations array. Deform only modifier need this type of * float array rather than MVert*. Tracked along with mesh_final as an * optimization to avoid copying coordinates back and forth if there are * multiple sequential deform only modifiers. */ - float(*deformed_verts)[3] = NULL; + float(*deformed_verts)[3] = nullptr; int num_deformed_verts = 0; bool isPrevDeform = false; /* Mesh with constructive modifiers but no deformation applied. Tracked * along with final mesh if undeformed / orco coordinates are requested * for texturing. */ - Mesh *mesh_orco = NULL; + Mesh *mesh_orco = nullptr; /* Modifier evaluation modes. */ const int required_mode = eModifierMode_Realtime | eModifierMode_Editmode; const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); /* Modifier evaluation contexts for different types of modifiers. */ - ModifierApplyFlag apply_render = use_render ? MOD_APPLY_RENDER : 0; - const ModifierEvalContext mectx = {depsgraph, ob, MOD_APPLY_USECACHE | apply_render}; + ModifierApplyFlag apply_render = use_render ? MOD_APPLY_RENDER : (ModifierApplyFlag)0; + const ModifierEvalContext mectx = { + depsgraph, ob, (ModifierApplyFlag)(MOD_APPLY_USECACHE | apply_render)}; const ModifierEvalContext mectx_orco = {depsgraph, ob, MOD_APPLY_ORCO}; /* Get effective list of modifiers to execute. Some effects like shape keys @@ -1508,24 +1587,24 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, * subdividing them is expensive. */ CustomData_MeshMasks final_datamask = *dataMask; CDMaskLink *datamasks = BKE_modifier_calc_data_masks( - scene, ob, md, &final_datamask, required_mode, NULL, NULL); + scene, ob, md, &final_datamask, required_mode, nullptr, nullptr); CDMaskLink *md_datamask = datamasks; CustomData_MeshMasks append_mask = CD_MASK_BAREMESH; /* Evaluate modifiers up to certain index to get the mesh cage. */ - int cageIndex = BKE_modifiers_get_cage_index(scene, ob, NULL, 1); + int cageIndex = BKE_modifiers_get_cage_index(scene, ob, nullptr, true); if (r_cage && cageIndex == -1) { mesh_cage = BKE_mesh_wrapper_from_editmesh_with_coords( - em_input, &final_datamask, NULL, mesh_input); + em_input, &final_datamask, nullptr, mesh_input); } /* Clear errors before evaluation. */ BKE_modifiers_clear_errors(ob); for (int i = 0; md; i++, md = md->next, md_datamask = md_datamask->next) { - const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type); - if (!editbmesh_modifier_is_enabled(scene, ob, md, mesh_final != NULL)) { + if (!editbmesh_modifier_is_enabled(scene, ob, md, mesh_final != nullptr)) { continue; } @@ -1555,11 +1634,11 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, } } else if (isPrevDeform && mti->dependsOnNormals && mti->dependsOnNormals(md)) { - if (mesh_final == NULL) { - mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, NULL, mesh_input); + if (mesh_final == nullptr) { + mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, nullptr, mesh_input); ASSERT_IS_VALID_MESH(mesh_final); } - BLI_assert(deformed_verts != NULL); + BLI_assert(deformed_verts != nullptr); BKE_mesh_vert_coords_apply(mesh_final, deformed_verts); } @@ -1577,7 +1656,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, if (deformed_verts) { Mesh *mesh_tmp = BKE_mesh_copy_for_eval(mesh_final, false); if (mesh_final != mesh_cage) { - BKE_id_free(NULL, mesh_final); + BKE_id_free(nullptr, mesh_final); } mesh_final = mesh_tmp; BKE_mesh_vert_coords_apply(mesh_final, deformed_verts); @@ -1589,8 +1668,8 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, } else { mesh_final = BKE_mesh_wrapper_from_editmesh_with_coords( - em_input, NULL, deformed_verts, mesh_input); - deformed_verts = NULL; + em_input, nullptr, deformed_verts, mesh_input); + deformed_verts = nullptr; } /* create an orco derivedmesh in parallel */ @@ -1612,7 +1691,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, if (mesh_next) { /* if the modifier returned a new dm, release the old one */ if (mesh_orco && mesh_orco != mesh_next) { - BKE_id_free(NULL, mesh_orco); + BKE_id_free(nullptr, mesh_orco); } mesh_orco = mesh_next; } @@ -1632,23 +1711,24 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, if (mask.lmask & CD_MASK_ORIGSPACE_MLOOP) { if (!CustomData_has_layer(&mesh_final->ldata, CD_ORIGSPACE_MLOOP)) { CustomData_add_layer( - &mesh_final->ldata, CD_ORIGSPACE_MLOOP, CD_CALLOC, NULL, mesh_final->totloop); + &mesh_final->ldata, CD_ORIGSPACE_MLOOP, CD_CALLOC, nullptr, mesh_final->totloop); mesh_init_origspace(mesh_final); } } - Mesh *mesh_next = BKE_modifier_modify_mesh(md, &mectx, mesh_final); + Mesh *mesh_next = modifier_modify_mesh_and_geometry_set( + md, mectx, ob, mesh_final, geometry_set_final); ASSERT_IS_VALID_MESH(mesh_next); if (mesh_next) { if (mesh_final && mesh_final != mesh_next) { - BKE_id_free(NULL, mesh_final); + BKE_id_free(nullptr, mesh_final); } mesh_final = mesh_next; if (deformed_verts) { MEM_freeN(deformed_verts); - deformed_verts = NULL; + deformed_verts = nullptr; } } mesh_final->runtime.deformed_only = false; @@ -1668,12 +1748,12 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, if (!BKE_mesh_runtime_ensure_edit_data(me_orig)) { BKE_mesh_runtime_reset_edit_data(me_orig); } - me_orig->runtime.edit_data->vertexCos = MEM_dupallocN(deformed_verts); + me_orig->runtime.edit_data->vertexCos = (float(*)[3])MEM_dupallocN(deformed_verts); } mesh_cage = BKE_mesh_wrapper_from_editmesh_with_coords( em_input, &final_datamask, - deformed_verts ? MEM_dupallocN(deformed_verts) : NULL, + deformed_verts ? (float(*)[3])MEM_dupallocN(deformed_verts) : nullptr, mesh_input); } } @@ -1681,7 +1761,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, isPrevDeform = (mti->type == eModifierTypeType_OnlyDeform); } - BLI_linklist_free((LinkNode *)datamasks, NULL); + BLI_linklist_free((LinkNode *)datamasks, nullptr); /* Yay, we are done. If we have a DerivedMesh and deformed vertices need * to apply these back onto the DerivedMesh. If we have no DerivedMesh @@ -1690,7 +1770,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, if (deformed_verts) { Mesh *mesh_tmp = BKE_mesh_copy_for_eval(mesh_final, false); if (mesh_final != mesh_cage) { - BKE_id_free(NULL, mesh_final); + BKE_id_free(nullptr, mesh_final); } mesh_final = mesh_tmp; BKE_mesh_vert_coords_apply(mesh_final, deformed_verts); @@ -1704,7 +1784,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, /* this is just a copy of the editmesh, no need to calc normals */ mesh_final = BKE_mesh_wrapper_from_editmesh_with_coords( em_input, &final_datamask, deformed_verts, mesh_input); - deformed_verts = NULL; + deformed_verts = nullptr; } if (deformed_verts) { @@ -1720,7 +1800,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, } if (mesh_orco) { - BKE_id_free(NULL, mesh_orco); + BKE_id_free(nullptr, mesh_orco); } /* Ensure normals calculation below is correct. */ @@ -1739,6 +1819,9 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, if (r_cage) { *r_cage = mesh_cage; } + if (r_geometry_set) { + *r_geometry_set = new GeometrySet(std::move(geometry_set_final)); + } } static void mesh_build_extra_data(struct Depsgraph *depsgraph, Object *ob, Mesh *mesh_eval) @@ -1784,7 +1867,8 @@ static void mesh_build_data(struct Depsgraph *depsgraph, } #endif - Mesh *mesh_eval = NULL, *mesh_deform_eval = NULL; + Mesh *mesh_eval = nullptr, *mesh_deform_eval = nullptr; + GeometrySet *geometry_set_eval = nullptr; mesh_calc_modifiers(depsgraph, scene, ob, @@ -1795,7 +1879,8 @@ static void mesh_build_data(struct Depsgraph *depsgraph, true, true, &mesh_deform_eval, - &mesh_eval); + &mesh_eval, + &geometry_set_eval); /* The modifier stack evaluation is storing result in mesh->runtime.mesh_eval, but this result * is not guaranteed to be owned by object. @@ -1803,10 +1888,16 @@ static void mesh_build_data(struct Depsgraph *depsgraph, * Check ownership now, since later on we can not go to a mesh owned by someone else via * object's runtime: this could cause access freed data on depsgraph destruction (mesh who owns * the final result might be freed prior to object). */ - Mesh *mesh = ob->data; + Mesh *mesh = (Mesh *)ob->data; const bool is_mesh_eval_owned = (mesh_eval != mesh->runtime.mesh_eval); BKE_object_eval_assign_data(ob, &mesh_eval->id, is_mesh_eval_owned); + /* Add the final mesh as read-only non-owning component to the geometry set. */ + BLI_assert(!geometry_set_eval->has<MeshComponent>()); + MeshComponent &mesh_component = geometry_set_eval->get_component_for_write<MeshComponent>(); + mesh_component.replace(mesh_eval, GeometryOwnershipType::ReadOnly); + ob->runtime.geometry_set_eval = geometry_set_eval; + ob->runtime.mesh_deform_eval = mesh_deform_eval; ob->runtime.last_data_mask = *dataMask; ob->runtime.last_need_mapping = need_mapping; @@ -1816,7 +1907,7 @@ static void mesh_build_data(struct Depsgraph *depsgraph, /* Make sure that drivers can target shapekey properties. * Note that this causes a potential inconsistency, as the shapekey may have a * different topology than the evaluated mesh. */ - BLI_assert(mesh->key == NULL || DEG_is_evaluated_id(&mesh->key->id)); + BLI_assert(mesh->key == nullptr || DEG_is_evaluated_id(&mesh->key->id)); mesh_eval->key = mesh->key; if ((ob->mode & OB_MODE_ALL_SCULPT) && ob->sculpt) { @@ -1846,11 +1937,14 @@ static void editbmesh_build_data(struct Depsgraph *depsgraph, Mesh *me_cage; Mesh *me_final; + GeometrySet *non_mesh_components; - editbmesh_calc_modifiers(depsgraph, scene, obedit, em, dataMask, &me_cage, &me_final); + editbmesh_calc_modifiers( + depsgraph, scene, obedit, em, dataMask, &me_cage, &me_final, &non_mesh_components); em->mesh_eval_final = me_final; em->mesh_eval_cage = me_cage; + obedit->runtime.geometry_set_eval = non_mesh_components; BKE_object_boundbox_calc_from_mesh(obedit, em->mesh_eval_final); @@ -1878,7 +1972,8 @@ static void object_get_datamask(const Depsgraph *depsgraph, return; } - Object *actob = view_layer->basact ? DEG_get_original_object(view_layer->basact->object) : NULL; + Object *actob = view_layer->basact ? DEG_get_original_object(view_layer->basact->object) : + nullptr; if (DEG_get_original_object(ob) == actob) { bool editing = BKE_paint_select_face_test(actob); @@ -1948,7 +2043,7 @@ Mesh *mesh_get_eval_final(struct Depsgraph *depsgraph, object_get_datamask(depsgraph, ob, &cddata_masks, &need_mapping); Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob); - if ((mesh_eval == NULL) || + if ((mesh_eval == nullptr) || !CustomData_MeshMasks_are_matching(&(ob->runtime.last_data_mask), &cddata_masks) || (need_mapping && !ob->runtime.last_need_mapping)) { CustomData_MeshMasks_update(&cddata_masks, &ob->runtime.last_data_mask); @@ -1957,7 +2052,7 @@ Mesh *mesh_get_eval_final(struct Depsgraph *depsgraph, mesh_eval = BKE_object_get_evaluated_mesh(ob); } - if (mesh_eval != NULL) { + if (mesh_eval != nullptr) { BLI_assert(!(mesh_eval->runtime.cd_dirty_vert & CD_MASK_NORMAL)); } return mesh_eval; @@ -2001,7 +2096,8 @@ Mesh *mesh_create_eval_final(Depsgraph *depsgraph, { Mesh *final; - mesh_calc_modifiers(depsgraph, scene, ob, 1, false, dataMask, -1, false, false, NULL, &final); + mesh_calc_modifiers( + depsgraph, scene, ob, 1, false, dataMask, -1, false, false, nullptr, &final, nullptr); return final; } @@ -2014,7 +2110,8 @@ Mesh *mesh_create_eval_final_index_render(Depsgraph *depsgraph, { Mesh *final; - mesh_calc_modifiers(depsgraph, scene, ob, 1, false, dataMask, index, false, false, NULL, &final); + mesh_calc_modifiers( + depsgraph, scene, ob, 1, false, dataMask, index, false, false, nullptr, &final, nullptr); return final; } @@ -2026,7 +2123,8 @@ Mesh *mesh_create_eval_no_deform(Depsgraph *depsgraph, { Mesh *final; - mesh_calc_modifiers(depsgraph, scene, ob, 0, false, dataMask, -1, false, false, NULL, &final); + mesh_calc_modifiers( + depsgraph, scene, ob, 0, false, dataMask, -1, false, false, nullptr, &final, nullptr); return final; } @@ -2038,7 +2136,8 @@ Mesh *mesh_create_eval_no_deform_render(Depsgraph *depsgraph, { Mesh *final; - mesh_calc_modifiers(depsgraph, scene, ob, 0, false, dataMask, -1, false, false, NULL, &final); + mesh_calc_modifiers( + depsgraph, scene, ob, 0, false, dataMask, -1, false, false, nullptr, &final, nullptr); return final; } @@ -2058,7 +2157,7 @@ Mesh *editbmesh_get_eval_cage_and_final(Depsgraph *depsgraph, /* if there's no derived mesh or the last data mask used doesn't include * the data we need, rebuild the derived mesh */ - object_get_datamask(depsgraph, obedit, &cddata_masks, NULL); + object_get_datamask(depsgraph, obedit, &cddata_masks, nullptr); if (!em->mesh_eval_cage || !CustomData_MeshMasks_are_matching(&(em->lastDataMask), &cddata_masks)) { @@ -2083,7 +2182,7 @@ Mesh *editbmesh_get_eval_cage(struct Depsgraph *depsgraph, /* if there's no derived mesh or the last data mask used doesn't include * the data we need, rebuild the derived mesh */ - object_get_datamask(depsgraph, obedit, &cddata_masks, NULL); + object_get_datamask(depsgraph, obedit, &cddata_masks, nullptr); if (!em->mesh_eval_cage || !CustomData_MeshMasks_are_matching(&(em->lastDataMask), &cddata_masks)) { @@ -2108,10 +2207,10 @@ Mesh *editbmesh_get_eval_cage_from_orig(struct Depsgraph *depsgraph, /***/ /* same as above but for vert coords */ -typedef struct { +struct MappedUserData { float (*vertexcos)[3]; BLI_bitmap *vertex_visit; -} MappedUserData; +}; static void make_vertexcos__mapFunc(void *userData, int index, @@ -2153,30 +2252,32 @@ void DM_calc_loop_tangents(DerivedMesh *dm, const char (*tangent_names)[MAX_NAME], int tangent_names_len) { - BKE_mesh_calc_loop_tangent_ex(dm->getVertArray(dm), - dm->getPolyArray(dm), - dm->getNumPolys(dm), - dm->getLoopArray(dm), - dm->getLoopTriArray(dm), - dm->getNumLoopTri(dm), - &dm->loopData, - calc_active_tangent, - tangent_names, - tangent_names_len, - CustomData_get_layer(&dm->polyData, CD_NORMAL), - dm->getLoopDataArray(dm, CD_NORMAL), - dm->getVertDataArray(dm, CD_ORCO), /* may be NULL */ - /* result */ - &dm->loopData, - dm->getNumLoops(dm), - &dm->tangent_mask); + BKE_mesh_calc_loop_tangent_ex( + dm->getVertArray(dm), + dm->getPolyArray(dm), + dm->getNumPolys(dm), + dm->getLoopArray(dm), + dm->getLoopTriArray(dm), + dm->getNumLoopTri(dm), + &dm->loopData, + calc_active_tangent, + tangent_names, + tangent_names_len, + (float(*)[3])CustomData_get_layer(&dm->polyData, CD_NORMAL), + (float(*)[3])dm->getLoopDataArray(dm, CD_NORMAL), + (float(*)[3])dm->getVertDataArray(dm, CD_ORCO), /* may be nullptr */ + /* result */ + &dm->loopData, + dm->getNumLoops(dm), + &dm->tangent_mask); } static void mesh_init_origspace(Mesh *mesh) { const float default_osf[4][2] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}}; - OrigSpaceLoop *lof_array = CustomData_get_layer(&mesh->ldata, CD_ORIGSPACE_MLOOP); + OrigSpaceLoop *lof_array = (OrigSpaceLoop *)CustomData_get_layer(&mesh->ldata, + CD_ORIGSPACE_MLOOP); const int numpoly = mesh->totpoly; // const int numloop = mesh->totloop; MVert *mv = mesh->mvert; @@ -2184,8 +2285,7 @@ static void mesh_init_origspace(Mesh *mesh) MPoly *mp = mesh->mpoly; int i, j, k; - float(*vcos_2d)[2] = NULL; - BLI_array_staticdeclare(vcos_2d, 64); + blender::Vector<blender::float2, 64> vcos_2d; for (i = 0; i < numpoly; i++, mp++) { OrigSpaceLoop *lof = lof_array + mp->loopstart; @@ -2206,8 +2306,7 @@ static void mesh_init_origspace(Mesh *mesh) BKE_mesh_calc_poly_normal(mp, l, mv, p_nor); axis_dominant_v3_to_m3(mat, p_nor); - BLI_array_clear(vcos_2d); - BLI_array_reserve(vcos_2d, mp->totloop); + vcos_2d.resize(mp->totloop); for (j = 0; j < mp->totloop; j++, l++) { mul_v3_m3v3(co, mat, mv[l->v].co); copy_v2_v2(vcos_2d[j], co); @@ -2245,7 +2344,6 @@ static void mesh_init_origspace(Mesh *mesh) } BKE_mesh_tessface_clear(mesh); - BLI_array_free(vcos_2d); } /* derivedmesh info printing function, @@ -2367,7 +2465,7 @@ bool DM_is_valid(DerivedMesh *dm) do_fixes, &changed); - is_valid &= BKE_mesh_validate_arrays(NULL, + is_valid &= BKE_mesh_validate_arrays(nullptr, dm->getVertArray(dm), dm->getNumVerts(dm), dm->getEdgeArray(dm), @@ -2378,7 +2476,7 @@ bool DM_is_valid(DerivedMesh *dm) dm->getNumLoops(dm), dm->getPolyArray(dm), dm->getNumPolys(dm), - dm->getVertDataArray(dm, CD_MDEFORMVERT), + (MDeformVert *)dm->getVertDataArray(dm, CD_MDEFORMVERT), do_verbose, do_fixes, &changed); diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c index 4d7ebba7064..521ebbfaf97 100644 --- a/source/blender/blenkernel/intern/anim_data.c +++ b/source/blender/blenkernel/intern/anim_data.c @@ -42,6 +42,7 @@ #include "DNA_ID.h" #include "DNA_anim_types.h" #include "DNA_light_types.h" +#include "DNA_material_types.h" #include "DNA_node_types.h" #include "DNA_space_types.h" #include "DNA_windowmanager_types.h" @@ -989,8 +990,8 @@ char *BKE_animsys_fix_rna_path_rename(ID *owner_id, char *name_old_esc = BLI_array_alloca(name_old_esc, (name_old_len * 2) + 1); char *name_new_esc = BLI_array_alloca(name_new_esc, (name_new_len * 2) + 1); - BLI_strescape(name_old_esc, oldName, (name_old_len * 2) + 1); - BLI_strescape(name_new_esc, newName, (name_new_len * 2) + 1); + BLI_str_escape(name_old_esc, oldName, (name_old_len * 2) + 1); + BLI_str_escape(name_new_esc, newName, (name_new_len * 2) + 1); oldN = BLI_sprintfN("[\"%s\"]", name_old_esc); newN = BLI_sprintfN("[\"%s\"]", name_new_esc); } @@ -1048,8 +1049,8 @@ void BKE_action_fix_paths_rename(ID *owner_id, char *name_old_esc = BLI_array_alloca(name_old_esc, (name_old_len * 2) + 1); char *name_new_esc = BLI_array_alloca(name_new_esc, (name_new_len * 2) + 1); - BLI_strescape(name_old_esc, oldName, (name_old_len * 2) + 1); - BLI_strescape(name_new_esc, newName, (name_new_len * 2) + 1); + BLI_str_escape(name_old_esc, oldName, (name_old_len * 2) + 1); + BLI_str_escape(name_new_esc, newName, (name_new_len * 2) + 1); oldN = BLI_sprintfN("[\"%s\"]", name_old_esc); newN = BLI_sprintfN("[\"%s\"]", name_new_esc); } @@ -1096,8 +1097,8 @@ void BKE_animdata_fix_paths_rename(ID *owner_id, char *name_old_esc = BLI_array_alloca(name_old_esc, (name_old_len * 2) + 1); char *name_new_esc = BLI_array_alloca(name_new_esc, (name_new_len * 2) + 1); - BLI_strescape(name_old_esc, oldName, (name_old_len * 2) + 1); - BLI_strescape(name_new_esc, newName, (name_new_len * 2) + 1); + BLI_str_escape(name_old_esc, oldName, (name_old_len * 2) + 1); + BLI_str_escape(name_new_esc, newName, (name_new_len * 2) + 1); oldN = BLI_sprintfN("[\"%s\"]", name_old_esc); newN = BLI_sprintfN("[\"%s\"]", name_new_esc); } diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 03c812b3b3d..ea41495d097 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -1189,7 +1189,7 @@ static void nlaeval_free(NlaEvalData *nlaeval) /* ---------------------- */ -static int nlaevalchan_validate_index(NlaEvalChannel *nec, int index) +static int nlaevalchan_validate_index(const NlaEvalChannel *nec, int index) { if (nec->is_array) { if (index >= 0 && index < nec->base_snapshot.length) { @@ -1201,6 +1201,28 @@ static int nlaevalchan_validate_index(NlaEvalChannel *nec, int index) return 0; } +static bool nlaevalchan_validate_index_ex(const NlaEvalChannel *nec, const int array_index) +{ + /** Although array_index comes from fcurve, that doesn't necessarily mean the property has that + * many elements. */ + const int index = nlaevalchan_validate_index(nec, array_index); + + if (index < 0) { + if (G.debug & G_DEBUG) { + ID *id = nec->key.ptr.owner_id; + CLOG_WARN(&LOG, + "Animation: Invalid array index. ID = '%s', '%s[%d]', array length is %d", + id ? (id->name + 2) : "<No ID>", + nec->rna_path, + array_index, + nec->base_snapshot.length); + } + + return false; + } + return true; +} + /* Initialize default values for NlaEvalChannel from the property data. */ static void nlaevalchan_get_default_values(NlaEvalChannel *nec, float *r_values) { @@ -1455,7 +1477,7 @@ static float nla_combine_value( return old_value + (value - base_value) * inf; case NEC_MIX_MULTIPLY: - if (base_value == 0.0f) { + if (IS_EQF(base_value, 0.0f)) { base_value = 1.0f; } return old_value * powf(value / base_value, inf); @@ -1471,6 +1493,11 @@ static float nla_combine_value( static bool nla_invert_blend_value( int blend_mode, float old_value, float target_value, float influence, float *r_value) { + /** No solution if strip had 0 influence. */ + if (IS_EQF(influence, 0.0f)) { + return false; + } + switch (blend_mode) { case NLASTRIP_MODE_ADD: *r_value = (target_value - old_value) / influence; @@ -1481,9 +1508,9 @@ static bool nla_invert_blend_value( return true; case NLASTRIP_MODE_MULTIPLY: - if (old_value == 0.0f) { + if (IS_EQF(old_value, 0.0f)) { /* Resolve 0/0 to 1. */ - if (target_value == 0.0f) { + if (IS_EQF(target_value, 0.0f)) { *r_value = 1.0f; return true; } @@ -1514,6 +1541,11 @@ static bool nla_invert_combine_value(int mix_mode, float influence, float *r_value) { + /* No solution if strip had no influence. */ + if (IS_EQF(influence, 0.0f)) { + return false; + } + switch (mix_mode) { case NEC_MIX_ADD: case NEC_MIX_AXIS_ANGLE: @@ -1521,12 +1553,12 @@ static bool nla_invert_combine_value(int mix_mode, return true; case NEC_MIX_MULTIPLY: - if (base_value == 0.0f) { + if (IS_EQF(base_value, 0.0f)) { base_value = 1.0f; } - if (old_value == 0.0f) { + if (IS_EQF(old_value, 0.0f)) { /* Resolve 0/0 to 1. */ - if (target_value == 0.0f) { + if (IS_EQF(target_value, 0.0f)) { *r_value = base_value; return true; } @@ -1560,11 +1592,14 @@ static void nla_combine_quaternion(const float old_values[4], } /* invert accumulation of quaternion channels for Combine mode according to influence */ -static void nla_invert_combine_quaternion(const float old_values[4], +static bool nla_invert_combine_quaternion(const float old_values[4], const float values[4], float influence, float result[4]) { + if (IS_EQF(influence, 0.0f)) { + return false; + } float tmp_old[4], tmp_new[4]; normalize_qt_qt(tmp_old, old_values); @@ -1573,6 +1608,8 @@ static void nla_invert_combine_quaternion(const float old_values[4], mul_qt_qtqt(result, tmp_old, tmp_new); pow_qt_fl_normalized(result, 1.0f / influence); + + return true; } /* Data about the current blend mode. */ @@ -1612,19 +1649,7 @@ static bool nlaeval_blend_value(NlaBlendData *blend, return false; } - int index = nlaevalchan_validate_index(nec, array_index); - - if (index < 0) { - if (G.debug & G_DEBUG) { - ID *id = nec->key.ptr.owner_id; - CLOG_WARN(&LOG, - "Animato: Invalid array index. ID = '%s', '%s[%d]', array length is %d", - id ? (id->name + 2) : "<No ID>", - nec->rna_path, - array_index, - nec->base_snapshot.length); - } - + if (!nlaevalchan_validate_index_ex(nec, array_index)) { return false; } @@ -1633,21 +1658,21 @@ static bool nlaeval_blend_value(NlaBlendData *blend, BLI_bitmap_set_all(nec->valid.ptr, true, 4); } else { - BLI_BITMAP_ENABLE(nec->valid.ptr, index); + BLI_BITMAP_ENABLE(nec->valid.ptr, array_index); } NlaEvalChannelSnapshot *nec_snapshot = nlaeval_snapshot_ensure_channel(blend->snapshot, nec); - float *p_value = &nec_snapshot->values[index]; + float *p_value = &nec_snapshot->values[array_index]; if (blend->mode == NLASTRIP_MODE_COMBINE) { /* Quaternion blending is deferred until all sub-channel values are known. */ if (nec->mix_mode == NEC_MIX_QUATERNION) { NlaEvalChannelSnapshot *blend_snapshot = nlaevalchan_queue_blend(blend, nec); - blend_snapshot->values[index] = value; + blend_snapshot->values[array_index] = value; } else { - float base_value = nec->base_snapshot.values[index]; + float base_value = nec->base_snapshot.values[array_index]; *p_value = nla_combine_value(nec->mix_mode, base_value, *p_value, value, blend->influence); } @@ -2502,7 +2527,9 @@ bool BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context, *r_force_all = true; - nla_invert_combine_quaternion(old_values, values, influence, values); + if (!nla_invert_combine_quaternion(old_values, values, influence, values)) { + return false; + } } else { float *base_values = nec->base_snapshot.values; diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c index b1462167edd..ae0c27635a6 100644 --- a/source/blender/blenkernel/intern/appdir.c +++ b/source/blender/blenkernel/intern/appdir.c @@ -36,6 +36,8 @@ #include "BKE_appdir.h" /* own include */ #include "BKE_blender_version.h" +#include "BLT_translation.h" + #include "GHOST_Path-api.h" #include "MEM_guardedalloc.h" @@ -146,47 +148,74 @@ static char *blender_version_decimal(const int version) * \{ */ /** - * This is now only used to really get the user's default document folder. + * Get the folder that's the "natural" starting point for browsing files on an OS. On Unix that is + * $HOME, on Windows it is %userprofile%/Documents. * - * \note On Windows `Users/{MyUserName}/Documents` is used - * as it's the default location to save documents. + * \note On Windows `Users/{MyUserName}/Documents` is used as it's the default location to save + * documents. */ const char *BKE_appdir_folder_default(void) { #ifndef WIN32 - const char *const xdg_documents_dir = BLI_getenv("XDG_DOCUMENTS_DIR"); + return BLI_getenv("HOME"); +#else /* Windows */ + static char documentfolder[MAXPATHLEN]; - if (xdg_documents_dir) { - return xdg_documents_dir; + if (BKE_appdir_folder_documents(documentfolder)) { + return documentfolder; } + return NULL; +#endif /* WIN32 */ +} + +/** + * Get the user's home directory, i.e. $HOME on UNIX, %userprofile% on Windows. + */ +const char *BKE_appdir_folder_home(void) +{ +#ifndef WIN32 return BLI_getenv("HOME"); -#else /* Windows */ - static char documentfolder[MAXPATHLEN]; - HRESULT hResult; +#else /* Windows */ + return BLI_getenv("userprofile"); +#endif +} - /* Check for `%HOME%` environment variable. */ - if (uput_getenv("HOME", documentfolder, MAXPATHLEN)) { - if (BLI_is_dir(documentfolder)) { - return documentfolder; - } +/** + * Get the user's document directory, i.e. $HOME/Documents on Linux, %userprofile%/Documents on + * Windows. If this can't be found using OS queries (via Ghost), try manually finding it. + * + * \returns True if the path is valid and points to an existing directory. + */ +bool BKE_appdir_folder_documents(char *dir) +{ + dir[0] = '\0'; + + const char *documents_path = (const char *)GHOST_getUserSpecialDir( + GHOST_kUserSpecialDirDocuments); + + /* Usual case: Ghost gave us the documents path. We're done here. */ + if (documents_path && BLI_is_dir(documents_path)) { + BLI_strncpy(dir, documents_path, FILE_MAXDIR); + return true; } - /* Add user profile support for WIN 2K / NT. - * This is `%APPDATA%`, which translates to either: - * - `%USERPROFILE%\Application Data` or... - * - `%USERPROFILE%\AppData\Roaming` (since Vista). - */ - hResult = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, documentfolder); + /* Ghost couldn't give us a documents path, let's try if we can find it ourselves.*/ - if (hResult == S_OK) { - if (BLI_is_dir(documentfolder)) { - return documentfolder; - } + const char *home_path = BKE_appdir_folder_home(); + if (!home_path || !BLI_is_dir(home_path)) { + return false; } - return NULL; -#endif /* WIN32 */ + char try_documents_path[FILE_MAXDIR]; + /* Own attempt at getting a valid Documents path. */ + BLI_path_join(try_documents_path, sizeof(try_documents_path), home_path, N_("Documents"), NULL); + if (!BLI_is_dir(try_documents_path)) { + return false; + } + + BLI_strncpy(dir, try_documents_path, FILE_MAXDIR); + return true; } /** @@ -877,14 +906,20 @@ bool BKE_appdir_program_python_search(char *fullpath, const char *python_build_def = STRINGIFY(PYTHON_EXECUTABLE_NAME); #endif const char *basename = "python"; +#if defined(WIN32) && !defined(NDEBUG) + const char *basename_debug = "python_d"; +#endif char python_version[16]; /* Check both possible names. */ const char *python_names[] = { #ifdef PYTHON_EXECUTABLE_NAME - python_build_def, + python_build_def, +#endif +#if defined(WIN32) && !defined(NDEBUG) + basename_debug, #endif - python_version, - basename, + python_version, + basename, }; bool is_found = false; diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 92146082557..ced211b1926 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -2441,7 +2441,7 @@ static void pose_proxy_sync(Object *ob, Object *from, int layer_protected) } /** - * \param r_last_visited_bone_p the last bone handled by the last call to this function. + * \param r_last_visited_bone_p: The last bone handled by the last call to this function. */ static int rebuild_pose_bone( bPose *pose, Bone *bone, bPoseChannel *parchan, int counter, Bone **r_last_visited_bone_p) diff --git a/source/blender/blenkernel/intern/asset.c b/source/blender/blenkernel/intern/asset.c new file mode 100644 index 00000000000..7ccb0aa2b57 --- /dev/null +++ b/source/blender/blenkernel/intern/asset.c @@ -0,0 +1,151 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup bke + */ + +#include <string.h> + +#include "BLI_listbase.h" +#include "BLI_string.h" +#include "BLI_string_utils.h" +#include "BLI_utildefines.h" + +#include "BKE_asset.h" +#include "BKE_icons.h" +#include "BKE_idprop.h" + +#include "DNA_ID.h" +#include "DNA_asset_types.h" +#include "DNA_defaults.h" + +#include "BLO_read_write.h" + +#include "MEM_guardedalloc.h" + +AssetMetaData *BKE_asset_metadata_create(void) +{ + AssetMetaData *asset_data = MEM_callocN(sizeof(*asset_data), __func__); + memcpy(asset_data, DNA_struct_default_get(AssetMetaData), sizeof(*asset_data)); + return asset_data; +} + +void BKE_asset_metadata_free(AssetMetaData **asset_data) +{ + if ((*asset_data)->properties) { + IDP_FreeProperty((*asset_data)->properties); + } + MEM_SAFE_FREE((*asset_data)->description); + BLI_freelistN(&(*asset_data)->tags); + + MEM_SAFE_FREE(*asset_data); +} + +static AssetTag *asset_metadata_tag_add(AssetMetaData *asset_data, const char *const name) +{ + AssetTag *tag = MEM_callocN(sizeof(*tag), __func__); + BLI_strncpy(tag->name, name, sizeof(tag->name)); + + BLI_addtail(&asset_data->tags, tag); + asset_data->tot_tags++; + /* Invariant! */ + BLI_assert(BLI_listbase_count(&asset_data->tags) == asset_data->tot_tags); + + return tag; +} + +AssetTag *BKE_asset_metadata_tag_add(AssetMetaData *asset_data, const char *name) +{ + AssetTag *tag = asset_metadata_tag_add(asset_data, name); + BLI_uniquename(&asset_data->tags, tag, name, '.', offsetof(AssetTag, name), sizeof(tag->name)); + return tag; +} + +/** + * Make sure there is a tag with name \a name, create one if needed. + */ +struct AssetTagEnsureResult BKE_asset_metadata_tag_ensure(AssetMetaData *asset_data, + const char *name) +{ + struct AssetTagEnsureResult result = {.tag = NULL}; + if (!name[0]) { + return result; + } + + AssetTag *tag = BLI_findstring(&asset_data->tags, name, offsetof(AssetTag, name)); + + if (tag) { + result.tag = tag; + result.is_new = false; + return result; + } + + tag = asset_metadata_tag_add(asset_data, name); + + result.tag = tag; + result.is_new = true; + return result; +} + +void BKE_asset_metadata_tag_remove(AssetMetaData *asset_data, AssetTag *tag) +{ + BLI_assert(BLI_findindex(&asset_data->tags, tag) >= 0); + BLI_freelinkN(&asset_data->tags, tag); + asset_data->tot_tags--; + /* Invariant! */ + BLI_assert(BLI_listbase_count(&asset_data->tags) == asset_data->tot_tags); +} + +/* Queries -------------------------------------------- */ + +PreviewImage *BKE_asset_metadata_preview_get_from_id(const AssetMetaData *UNUSED(asset_data), + const ID *id) +{ + return BKE_previewimg_id_get(id); +} + +/* .blend file API -------------------------------------------- */ + +void BKE_asset_metadata_write(BlendWriter *writer, AssetMetaData *asset_data) +{ + BLO_write_struct(writer, AssetMetaData, asset_data); + + if (asset_data->properties) { + IDP_BlendWrite(writer, asset_data->properties); + } + + if (asset_data->description) { + BLO_write_string(writer, asset_data->description); + } + LISTBASE_FOREACH (AssetTag *, tag, &asset_data->tags) { + BLO_write_struct(writer, AssetTag, tag); + } +} + +void BKE_asset_metadata_read(BlendDataReader *reader, AssetMetaData *asset_data) +{ + /* asset_data itself has been read already. */ + + if (asset_data->properties) { + BLO_read_data_address(reader, &asset_data->properties); + IDP_BlendDataRead(reader, &asset_data->properties); + } + + BLO_read_data_address(reader, &asset_data->description); + BLO_read_list(reader, &asset_data->tags); + BLI_assert(BLI_listbase_count(&asset_data->tags) == asset_data->tot_tags); +} diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index 9f5795291f0..934beb8a848 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -392,6 +392,8 @@ const blender::fn::CPPType *custom_data_type_to_cpp_type(const CustomDataType ty return &CPPType::get<int>(); case CD_PROP_COLOR: return &CPPType::get<Color4f>(); + case CD_PROP_BOOL: + return &CPPType::get<bool>(); default: return nullptr; } @@ -415,6 +417,9 @@ CustomDataType cpp_type_to_custom_data_type(const blender::fn::CPPType &type) if (type.is<Color4f>()) { return CD_PROP_COLOR; } + if (type.is<bool>()) { + return CD_PROP_BOOL; + } return static_cast<CustomDataType>(-1); } @@ -449,6 +454,9 @@ static ReadAttributePtr read_attribute_from_custom_data(const CustomData &custom case CD_PROP_COLOR: return std::make_unique<ArrayReadAttribute<Color4f>>( domain, Span(static_cast<Color4f *>(layer.data), size)); + case CD_PROP_BOOL: + return std::make_unique<ArrayReadAttribute<bool>>( + domain, Span(static_cast<bool *>(layer.data), size)); } } } @@ -490,6 +498,9 @@ static WriteAttributePtr write_attribute_from_custom_data( case CD_PROP_COLOR: return std::make_unique<ArrayWriteAttribute<Color4f>>( domain, MutableSpan(static_cast<Color4f *>(layer.data), size)); + case CD_PROP_BOOL: + return std::make_unique<ArrayWriteAttribute<bool>>( + domain, MutableSpan(static_cast<bool *>(layer.data), size)); } } } @@ -590,6 +601,15 @@ Set<std::string> GeometryComponent::attribute_names() const return {}; } +bool GeometryComponent::attribute_exists(const blender::StringRef attribute_name) const +{ + ReadAttributePtr attribute = this->attribute_try_get_for_read(attribute_name); + if (attribute) { + return true; + } + return false; +} + static ReadAttributePtr try_adapt_data_type(ReadAttributePtr attribute, const blender::fn::CPPType &to_type) { @@ -640,6 +660,28 @@ ReadAttributePtr GeometryComponent::attribute_try_get_for_read( return attribute; } +ReadAttributePtr GeometryComponent::attribute_try_get_for_read(const StringRef attribute_name, + const AttributeDomain domain) const +{ + if (!this->attribute_domain_supported(domain)) { + return {}; + } + + ReadAttributePtr attribute = this->attribute_try_get_for_read(attribute_name); + if (!attribute) { + return {}; + } + + if (attribute->domain() != domain) { + attribute = this->attribute_try_adapt_domain(std::move(attribute), domain); + if (!attribute) { + return {}; + } + } + + return attribute; +} + ReadAttributePtr GeometryComponent::attribute_get_for_read(const StringRef attribute_name, const AttributeDomain domain, const CustomDataType data_type, @@ -668,6 +710,39 @@ blender::bke::ReadAttributePtr GeometryComponent::attribute_get_constant_for_rea domain, domain_size, *cpp_type, value); } +blender::bke::ReadAttributePtr GeometryComponent::attribute_get_constant_for_read_converted( + const AttributeDomain domain, + const CustomDataType in_data_type, + const CustomDataType out_data_type, + const void *value) const +{ + BLI_assert(this->attribute_domain_supported(domain)); + if (value == nullptr || in_data_type == out_data_type) { + return this->attribute_get_constant_for_read(domain, out_data_type, value); + } + + const blender::fn::CPPType *in_cpp_type = blender::bke::custom_data_type_to_cpp_type( + in_data_type); + const blender::fn::CPPType *out_cpp_type = blender::bke::custom_data_type_to_cpp_type( + out_data_type); + BLI_assert(in_cpp_type != nullptr); + BLI_assert(out_cpp_type != nullptr); + + const blender::nodes::DataTypeConversions &conversions = + blender::nodes::get_implicit_type_conversions(); + BLI_assert(conversions.is_convertible(*in_cpp_type, *out_cpp_type)); + + void *out_value = alloca(out_cpp_type->size()); + conversions.convert(*in_cpp_type, *out_cpp_type, value, out_value); + + const int domain_size = this->attribute_domain_size(domain); + blender::bke::ReadAttributePtr attribute = std::make_unique<blender::bke::ConstantReadAttribute>( + domain, domain_size, *out_cpp_type, out_value); + + out_cpp_type->destruct(out_value); + return attribute; +} + WriteAttributePtr GeometryComponent::attribute_try_ensure_for_write(const StringRef attribute_name, const AttributeDomain domain, const CustomDataType data_type) @@ -709,6 +784,7 @@ bool PointCloudComponent::attribute_domain_with_type_supported( const AttributeDomain domain, const CustomDataType data_type) const { return domain == ATTR_DOMAIN_POINT && ELEM(data_type, + CD_PROP_BOOL, CD_PROP_FLOAT, CD_PROP_FLOAT2, CD_PROP_FLOAT3, @@ -832,8 +908,13 @@ bool MeshComponent::attribute_domain_with_type_supported(const AttributeDomain d if (!this->attribute_domain_supported(domain)) { return false; } - return ELEM( - data_type, CD_PROP_FLOAT, CD_PROP_FLOAT2, CD_PROP_FLOAT3, CD_PROP_INT32, CD_PROP_COLOR); + return ELEM(data_type, + CD_PROP_BOOL, + CD_PROP_FLOAT, + CD_PROP_FLOAT2, + CD_PROP_FLOAT3, + CD_PROP_INT32, + CD_PROP_COLOR); } int MeshComponent::attribute_domain_size(const AttributeDomain domain) const diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index f4f25c3a153..5b5bd416ef2 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -296,6 +296,7 @@ void BKE_blender_userdef_data_free(UserDef *userdef, bool clear_fonts) } BLI_freelistN(&userdef->autoexec_paths); + BLI_freelistN(&userdef->asset_libraries); BLI_freelistN(&userdef->uistyles); BLI_freelistN(&userdef->uifonts); diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c index 567773507cf..0855db1a943 100644 --- a/source/blender/blenkernel/intern/blendfile.c +++ b/source/blender/blenkernel/intern/blendfile.c @@ -52,6 +52,7 @@ #include "BKE_layer.h" #include "BKE_lib_id.h" #include "BKE_main.h" +#include "BKE_preferences.h" #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_screen.h" @@ -645,6 +646,8 @@ UserDef *BKE_blendfile_userdef_from_defaults(void) /* Default studio light. */ BKE_studiolight_default(userdef->light_param, userdef->light_ambient); + BKE_preferences_asset_library_default_add(userdef); + return userdef; } diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c index 96bf9fbe8d2..e69173cc1d5 100644 --- a/source/blender/blenkernel/intern/boids.c +++ b/source/blender/blenkernel/intern/boids.c @@ -39,6 +39,7 @@ #include "BKE_collision.h" #include "BKE_effect.h" #include "BKE_particle.h" +#include "BLI_kdopbvh.h" #include "BKE_modifier.h" diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c index f624d0ae057..762ced7dc5f 100644 --- a/source/blender/blenkernel/intern/bpath.c +++ b/source/blender/blenkernel/intern/bpath.c @@ -78,7 +78,7 @@ #include "CLG_log.h" -#include "SEQ_sequencer.h" +#include "SEQ_iterator.h" #ifndef _MSC_VER # include "BLI_strict_flags.h" diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 561623da41f..9c17bfac9ec 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -23,6 +23,7 @@ #include "DNA_brush_types.h" #include "DNA_defaults.h" #include "DNA_gpencil_types.h" +#include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -1840,6 +1841,13 @@ void BKE_brush_sculpt_reset(Brush *br) br->surface_smooth_shape_preservation = 0.5f; br->surface_smooth_current_vertex = 0.5f; br->surface_smooth_iterations = 4; + case SCULPT_TOOL_DISPLACEMENT_SMEAR: + br->alpha = 1.0f; + br->spacing = 5; + br->hardness = 0.7f; + br->flag &= ~BRUSH_ALPHA_PRESSURE; + br->flag &= ~BRUSH_SPACE_ATTEN; + br->curve_preset = BRUSH_CURVE_SMOOTHER; break; default: break; @@ -1906,6 +1914,7 @@ void BKE_brush_sculpt_reset(Brush *br) case SCULPT_TOOL_MASK: case SCULPT_TOOL_DRAW_FACE_SETS: case SCULPT_TOOL_DISPLACEMENT_ERASER: + case SCULPT_TOOL_DISPLACEMENT_SMEAR: br->add_col[0] = 0.75f; br->add_col[1] = 0.75f; br->add_col[2] = 0.75f; diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index 5eec788255d..b86b59066d6 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -1773,6 +1773,15 @@ static void layer_collection_flags_store(Main *bmain, } } +static void layer_collection_flags_free_recursive(LayerCollectionFlag *flag) +{ + LISTBASE_FOREACH (LayerCollectionFlag *, child, &flag->children) { + layer_collection_flags_free_recursive(child); + } + + BLI_freelistN(&flag->children); +} + static void layer_collection_flags_restore_recursive(LayerCollection *layer_collection, LayerCollectionFlag *flag) { @@ -1788,7 +1797,6 @@ static void layer_collection_flags_restore_recursive(LayerCollection *layer_coll child_flag = child_flag->next; } - BLI_freelistN(&flag->children); /* We treat exclude as a special case. * @@ -1814,10 +1822,15 @@ static void layer_collection_flags_restore(ListBase *flags, const Collection *co LayerCollection *layer_collection = BKE_layer_collection_first_from_scene_collection( view_layer, collection); - /* The flags should only be added if the collection is in the view layer. */ - BLI_assert(layer_collection != NULL); - - layer_collection_flags_restore_recursive(layer_collection, flag); + /* Check that the collection is still in the scene (and therefore its view layers). In most + * cases this is true, but if we move a sub-collection shared by several scenes to a collection + * local to the target scene, it is effectively removed from every other scene's hierarchy + * (e.g. moving into current scene's master collection). Then the other scene's view layers + * won't contain a matching layer collection anymore, so there is nothing to restore to. */ + if (layer_collection != NULL) { + layer_collection_flags_restore_recursive(layer_collection, flag); + } + layer_collection_flags_free_recursive(flag); } BLI_freelistN(flags); @@ -1877,7 +1890,7 @@ bool BKE_collection_move(Main *bmain, /* Create and remove layer collections. */ BKE_main_collection_sync(bmain); - /* Restore the original layer collection flags. */ + /* Restore the original layer collection flags and free their temporary storage. */ if (do_flag_sync) { layer_collection_flags_restore(&layer_flags, collection); } diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 982e91dd1e0..b6f84dfc42f 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -5957,16 +5957,15 @@ static bConstraint *constraint_find_original_for_update(bConstraintOb *cob, bCon } /** - * Check whether given constraint is local when the object is a library override. + * Check whether given constraint is not local (i.e. from linked data) when the object is a library + * override. * - * \param con May be NULL, in which case we consider it as a non-local constraint case. - * - * \note This check is only valid for a liboverride data-block, it always return \a true otherwise. + * \param con: May be NULL, in which case we consider it as a non-local constraint case. */ -bool BKE_constraint_is_local_in_liboverride(const Object *ob, const bConstraint *con) +bool BKE_constraint_is_nonlocal_in_liboverride(const Object *ob, const bConstraint *con) { - return (!ID_IS_OVERRIDE_LIBRARY(ob) || - (con != NULL && (con->flag & CONSTRAINT_OVERRIDE_LIBRARY_LOCAL) != 0)); + return (ID_IS_OVERRIDE_LIBRARY(ob) && + (con == NULL || (con->flag & CONSTRAINT_OVERRIDE_LIBRARY_LOCAL) == 0)); } /* -------- Constraints and Proxies ------- */ diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c index a1edfd1c56d..65accc66084 100644 --- a/source/blender/blenkernel/intern/context.c +++ b/source/blender/blenkernel/intern/context.c @@ -123,7 +123,7 @@ void CTX_free(bContext *C) /* store */ -bContextStore *CTX_store_add(ListBase *contexts, const char *name, PointerRNA *ptr) +bContextStore *CTX_store_add(ListBase *contexts, const char *name, const PointerRNA *ptr) { /* ensure we have a context to put the entry in, if it was already used * we have to copy the context to ensure */ @@ -178,6 +178,11 @@ bContextStore *CTX_store_add_all(ListBase *contexts, bContextStore *context) return ctx; } +bContextStore *CTX_store_get(bContext *C) +{ + return C->wm.store; +} + void CTX_store_set(bContext *C, bContextStore *store) { C->wm.store = store; @@ -1202,6 +1207,11 @@ ToolSettings *CTX_data_tool_settings(const bContext *C) return NULL; } +int CTX_data_selected_ids(const bContext *C, ListBase *list) +{ + return ctx_data_collection_get(C, "selected_ids", list); +} + int CTX_data_selected_nodes(const bContext *C, ListBase *list) { return ctx_data_collection_get(C, "selected_nodes", list); diff --git a/source/blender/blenkernel/intern/cryptomatte.c b/source/blender/blenkernel/intern/cryptomatte.c deleted file mode 100644 index 6570ffce920..00000000000 --- a/source/blender/blenkernel/intern/cryptomatte.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2008 Blender Foundation. - * All rights reserved. - */ - -/** \file - * \ingroup bke - */ - -#include "BKE_cryptomatte.h" - -#include "DNA_material_types.h" -#include "DNA_object_types.h" - -#include "BLI_compiler_attrs.h" -#include "BLI_hash_mm3.h" -#include "BLI_string.h" -#include <string.h> - -static uint32_t cryptomatte_hash(const ID *id) -{ - const char *name = &id->name[2]; - const int len = BLI_strnlen(name, MAX_NAME - 2); - uint32_t cryptohash_int = BLI_hash_mm3((const unsigned char *)name, len, 0); - return cryptohash_int; -} - -uint32_t BKE_cryptomatte_object_hash(const Object *object) -{ - return cryptomatte_hash(&object->id); -} - -uint32_t BKE_cryptomatte_material_hash(const Material *material) -{ - if (material == NULL) { - return 0.0f; - } - return cryptomatte_hash(&material->id); -} - -uint32_t BKE_cryptomatte_asset_hash(const Object *object) -{ - const Object *asset_object = object; - while (asset_object->parent != NULL) { - asset_object = asset_object->parent; - } - return cryptomatte_hash(&asset_object->id); -} - -/* Convert a cryptomatte hash to a float. - * - * Cryptomatte hashes are stored in float textures and images. The conversion is taken from the - * cryptomatte specification. See Floating point conversion section in - * https://github.com/Psyop/Cryptomatte/blob/master/specification/cryptomatte_specification.pdf. - * - * The conversion uses as many 32 bit floating point values as possible to minimize hash - * collisions. Unfortunately not all 32 bits can be as NaN and Inf can be problematic. - * - * Note that this conversion assumes to be running on a L-endian system. */ -float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash) -{ - uint32_t mantissa = cryptomatte_hash & ((1 << 23) - 1); - uint32_t exponent = (cryptomatte_hash >> 23) & ((1 << 8) - 1); - exponent = MAX2(exponent, (uint32_t)1); - exponent = MIN2(exponent, (uint32_t)254); - exponent = exponent << 23; - uint32_t sign = (cryptomatte_hash >> 31); - sign = sign << 31; - uint32_t float_bits = sign | exponent | mantissa; - float f; - memcpy(&f, &float_bits, sizeof(uint32_t)); - return f; -} diff --git a/source/blender/blenkernel/intern/cryptomatte.cc b/source/blender/blenkernel/intern/cryptomatte.cc new file mode 100644 index 00000000000..4bbeb088628 --- /dev/null +++ b/source/blender/blenkernel/intern/cryptomatte.cc @@ -0,0 +1,190 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup bke + */ + +#include "BKE_cryptomatte.h" +#include "BKE_main.h" + +#include "DNA_material_types.h" +#include "DNA_node_types.h" +#include "DNA_object_types.h" + +#include "BLI_compiler_attrs.h" +#include "BLI_dynstr.h" +#include "BLI_hash_mm3.h" +#include "BLI_listbase.h" +#include "BLI_string.h" + +#include "MEM_guardedalloc.h" + +#include <cstring> +#include <sstream> +#include <string> + +static uint32_t cryptomatte_hash(const ID *id) +{ + const char *name = &id->name[2]; + const int name_len = BLI_strnlen(name, MAX_NAME); + uint32_t cryptohash_int = BKE_cryptomatte_hash(name, name_len); + return cryptohash_int; +} + +uint32_t BKE_cryptomatte_hash(const char *name, int name_len) +{ + uint32_t cryptohash_int = BLI_hash_mm3((const unsigned char *)name, name_len, 0); + return cryptohash_int; +} + +uint32_t BKE_cryptomatte_object_hash(const Object *object) +{ + return cryptomatte_hash(&object->id); +} + +uint32_t BKE_cryptomatte_material_hash(const Material *material) +{ + if (material == nullptr) { + return 0.0f; + } + return cryptomatte_hash(&material->id); +} + +uint32_t BKE_cryptomatte_asset_hash(const Object *object) +{ + const Object *asset_object = object; + while (asset_object->parent != nullptr) { + asset_object = asset_object->parent; + } + return cryptomatte_hash(&asset_object->id); +} + +/* Convert a cryptomatte hash to a float. + * + * Cryptomatte hashes are stored in float textures and images. The conversion is taken from the + * cryptomatte specification. See Floating point conversion section in + * https://github.com/Psyop/Cryptomatte/blob/master/specification/cryptomatte_specification.pdf. + * + * The conversion uses as many 32 bit floating point values as possible to minimize hash + * collisions. Unfortunately not all 32 bits can be as NaN and Inf can be problematic. + * + * Note that this conversion assumes to be running on a L-endian system. */ +float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash) +{ + uint32_t mantissa = cryptomatte_hash & ((1 << 23) - 1); + uint32_t exponent = (cryptomatte_hash >> 23) & ((1 << 8) - 1); + exponent = MAX2(exponent, (uint32_t)1); + exponent = MIN2(exponent, (uint32_t)254); + exponent = exponent << 23; + uint32_t sign = (cryptomatte_hash >> 31); + sign = sign << 31; + uint32_t float_bits = sign | exponent | mantissa; + float f; + memcpy(&f, &float_bits, sizeof(uint32_t)); + return f; +} + +static ID *cryptomatte_find_id(const ListBase *ids, const float encoded_hash) +{ + LISTBASE_FOREACH (ID *, id, ids) { + uint32_t hash = BKE_cryptomatte_hash((id->name + 2), BLI_strnlen(id->name + 2, MAX_NAME)); + if (BKE_cryptomatte_hash_to_float(hash) == encoded_hash) { + return id; + } + } + return nullptr; +} + +/* Find an ID in the given main that matches the given encoded float. */ +static struct ID *BKE_cryptomatte_find_id(const Main *bmain, const float encoded_hash) +{ + ID *result; + result = cryptomatte_find_id(&bmain->objects, encoded_hash); + if (result == nullptr) { + result = cryptomatte_find_id(&bmain->materials, encoded_hash); + } + return result; +} + +char *BKE_cryptomatte_entries_to_matte_id(NodeCryptomatte *node_storage) +{ + DynStr *matte_id = BLI_dynstr_new(); + bool first = true; + LISTBASE_FOREACH (CryptomatteEntry *, entry, &node_storage->entries) { + if (!first) { + BLI_dynstr_append(matte_id, ","); + } + if (BLI_strnlen(entry->name, sizeof(entry->name)) != 0) { + BLI_dynstr_nappend(matte_id, entry->name, sizeof(entry->name)); + } + else { + BLI_dynstr_appendf(matte_id, "<%.9g>", entry->encoded_hash); + } + first = false; + } + char *result = BLI_dynstr_get_cstring(matte_id); + BLI_dynstr_free(matte_id); + return result; +} + +void BKE_cryptomatte_matte_id_to_entries(const Main *bmain, + NodeCryptomatte *node_storage, + const char *matte_id) +{ + BLI_freelistN(&node_storage->entries); + + std::istringstream ss(matte_id); + while (ss.good()) { + CryptomatteEntry *entry = nullptr; + std::string token; + getline(ss, token, ','); + /* Ignore empty tokens. */ + if (token.length() > 0) { + size_t first = token.find_first_not_of(' '); + size_t last = token.find_last_not_of(' '); + if (first == std::string::npos || last == std::string::npos) { + break; + } + token = token.substr(first, (last - first + 1)); + if (*token.begin() == '<' && *(--token.end()) == '>') { + float encoded_hash = atof(token.substr(1, token.length() - 2).c_str()); + entry = (CryptomatteEntry *)MEM_callocN(sizeof(CryptomatteEntry), __func__); + entry->encoded_hash = encoded_hash; + if (bmain) { + ID *id = BKE_cryptomatte_find_id(bmain, encoded_hash); + if (id != nullptr) { + BLI_strncpy(entry->name, id->name + 2, sizeof(entry->name)); + } + } + } + else { + const char *name = token.c_str(); + int name_len = token.length(); + entry = (CryptomatteEntry *)MEM_callocN(sizeof(CryptomatteEntry), __func__); + BLI_strncpy(entry->name, name, sizeof(entry->name)); + uint32_t hash = BKE_cryptomatte_hash(name, name_len); + entry->encoded_hash = BKE_cryptomatte_hash_to_float(hash); + } + } + if (entry != nullptr) { + BLI_addtail(&node_storage->entries, entry); + } + } +}
\ No newline at end of file diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 2df9f362b9c..ebce28c4e23 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -2185,19 +2185,28 @@ static void bevel_list_calc_bisect(BevList *bl) bevp2++; } + /* In the unlikely situation that handles define a zeroed direction, + * calculate it from the adjacent points, see T80742. + * + * Only do this as a fallback since we typically want the end-point directions + * to be exactly aligned with the handles at the end-point, see T83117. */ if (is_cyclic == false) { bevp0 = &bl->bevpoints[0]; bevp1 = &bl->bevpoints[1]; - sub_v3_v3v3(bevp0->dir, bevp1->vec, bevp0->vec); - if (normalize_v3(bevp0->dir) == 0.0f) { - copy_v3_v3(bevp0->dir, bevp1->dir); + if (UNLIKELY(is_zero_v3(bevp0->dir))) { + sub_v3_v3v3(bevp0->dir, bevp1->vec, bevp0->vec); + if (normalize_v3(bevp0->dir) == 0.0f) { + copy_v3_v3(bevp0->dir, bevp1->dir); + } } bevp0 = &bl->bevpoints[bl->nr - 2]; bevp1 = &bl->bevpoints[bl->nr - 1]; - sub_v3_v3v3(bevp1->dir, bevp1->vec, bevp0->vec); - if (normalize_v3(bevp1->dir) == 0.0f) { - copy_v3_v3(bevp1->dir, bevp0->dir); + if (UNLIKELY(is_zero_v3(bevp1->dir))) { + sub_v3_v3v3(bevp1->dir, bevp1->vec, bevp0->vec); + if (normalize_v3(bevp1->dir) == 0.0f) { + copy_v3_v3(bevp1->dir, bevp0->dir); + } } } } diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 0c89c3fead9..c4384fa8343 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -1863,6 +1863,21 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { layerMultiply_propfloat2, NULL, layerAdd_propfloat2}, + /* 50: CD_PROP_POOL */ + {sizeof(bool), + "bool", + 1, + N_("Boolean"), + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL}, }; static const char *LAYERTYPENAMES[CD_NUMTYPES] = { @@ -1918,6 +1933,7 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = { "CDPropCol", "CDPropFloat3", "CDPropFloat2", + "CDPropBoolean", }; const CustomData_MeshMasks CD_MASK_BAREMESH = { diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index b56a15b3d45..e18b2d87459 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -42,6 +42,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" +#include "DNA_object_force_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_texture_types.h" diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c index 9431915b4e4..df1dbaa905f 100644 --- a/source/blender/blenkernel/intern/font.c +++ b/source/blender/blenkernel/intern/font.c @@ -125,11 +125,17 @@ static void vfont_free_data(ID *id) static void vfont_blend_write(BlendWriter *writer, ID *id, const void *id_address) { VFont *vf = (VFont *)id; - if (vf->id.us > 0 || BLO_write_is_undo(writer)) { + const bool is_undo = BLO_write_is_undo(writer); + if (vf->id.us > 0 || is_undo) { /* Clean up, important in undo case to reduce false detection of changed datablocks. */ vf->data = NULL; vf->temp_pf = NULL; + /* Do not store packed files in case this is a library override ID. */ + if (ID_IS_OVERRIDE_LIBRARY(vf) && !is_undo) { + vf->packedfile = NULL; + } + /* write LibData */ BLO_write_id_struct(writer, VFont, id_address, &vf->id); BKE_id_blend_write(writer, &vf->id); diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc index 28695d769d3..e6a67b191f8 100644 --- a/source/blender/blenkernel/intern/geometry_set.cc +++ b/source/blender/blenkernel/intern/geometry_set.cc @@ -460,31 +460,54 @@ GeometryComponent *InstancesComponent::copy() const new_component->positions_ = positions_; new_component->rotations_ = rotations_; new_component->scales_ = scales_; - new_component->objects_ = objects_; + new_component->instanced_data_ = instanced_data_; return new_component; } void InstancesComponent::clear() { - objects_.clear(); + instanced_data_.clear(); positions_.clear(); rotations_.clear(); scales_.clear(); } -void InstancesComponent::add_instance(const Object *object, + +void InstancesComponent::add_instance(Object *object, + blender::float3 position, + blender::float3 rotation, + blender::float3 scale) +{ + InstancedData data; + data.type = INSTANCE_DATA_TYPE_OBJECT; + data.data.object = object; + this->add_instance(data, position, rotation, scale); +} + +void InstancesComponent::add_instance(Collection *collection, + blender::float3 position, + blender::float3 rotation, + blender::float3 scale) +{ + InstancedData data; + data.type = INSTANCE_DATA_TYPE_COLLECTION; + data.data.collection = collection; + this->add_instance(data, position, rotation, scale); +} + +void InstancesComponent::add_instance(InstancedData data, blender::float3 position, blender::float3 rotation, blender::float3 scale) { - objects_.append(object); + instanced_data_.append(data); positions_.append(position); rotations_.append(rotation); scales_.append(scale); } -Span<const Object *> InstancesComponent::objects() const +Span<InstancedData> InstancesComponent::instanced_data() const { - return objects_; + return instanced_data_; } Span<float3> InstancesComponent::positions() const @@ -509,8 +532,11 @@ MutableSpan<float3> InstancesComponent::positions() int InstancesComponent::instances_amount() const { - BLI_assert(positions_.size() == objects_.size()); - return objects_.size(); + const int size = instanced_data_.size(); + BLI_assert(positions_.size() == size); + BLI_assert(rotations_.size() == size); + BLI_assert(scales_.size() == size); + return size; } bool InstancesComponent::is_empty() const @@ -538,7 +564,7 @@ int BKE_geometry_set_instances(const GeometrySet *geometry_set, float (**r_positions)[3], float (**r_rotations)[3], float (**r_scales)[3], - Object ***r_objects) + InstancedData **r_instanced_data) { const InstancesComponent *component = geometry_set->get_component_for_read<InstancesComponent>(); if (component == nullptr) { @@ -547,7 +573,7 @@ int BKE_geometry_set_instances(const GeometrySet *geometry_set, *r_positions = (float(*)[3])component->positions().data(); *r_rotations = (float(*)[3])component->rotations().data(); *r_scales = (float(*)[3])component->scales().data(); - *r_objects = (Object **)component->objects().data(); + *r_instanced_data = (InstancedData *)component->instanced_data().data(); return component->instances_amount(); } diff --git a/source/blender/blenkernel/intern/gpencil_curve.c b/source/blender/blenkernel/intern/gpencil_curve.c index 8cc11468771..be14d74de7a 100644 --- a/source/blender/blenkernel/intern/gpencil_curve.c +++ b/source/blender/blenkernel/intern/gpencil_curve.c @@ -36,8 +36,11 @@ #include "BLT_translation.h" +#include "DNA_collection_types.h" #include "DNA_gpencil_types.h" +#include "DNA_material_types.h" #include "DNA_meshdata_types.h" +#include "DNA_scene_types.h" #include "BKE_collection.h" #include "BKE_context.h" diff --git a/source/blender/blenkernel/intern/gpencil_geom.c b/source/blender/blenkernel/intern/gpencil_geom.c index fc74439fd76..981f5d50353 100644 --- a/source/blender/blenkernel/intern/gpencil_geom.c +++ b/source/blender/blenkernel/intern/gpencil_geom.c @@ -34,6 +34,7 @@ #include "BLI_blenlib.h" #include "BLI_ghash.h" #include "BLI_hash.h" +#include "BLI_heap.h" #include "BLI_math_vector.h" #include "BLI_polyfill_2d.h" @@ -41,6 +42,7 @@ #include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" +#include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_scene_types.h" @@ -3224,4 +3226,197 @@ void BKE_gpencil_stroke_join(bGPDstroke *gps_a, gps_a, dvert, pt, delta, pt->pressure * ratio, pt->strength, deltatime); } } + +/* Stroke Uniform Subdivide ------------------------------------- */ + +typedef struct tSamplePoint { + struct tSamplePoint *next, *prev; + float x, y, z; + float pressure, strength, time; + float vertex_color[4]; + struct MDeformWeight *dw; + int totweight; +} tSamplePoint; + +typedef struct tSampleEdge { + float length_sq; + tSamplePoint *from; + tSamplePoint *to; +} tSampleEdge; + +/* Helper: creates a tSamplePoint from a bGPDspoint and (optionally) a MDeformVert. */ +static tSamplePoint *new_sample_point_from_gp_point(const bGPDspoint *pt, const MDeformVert *dvert) +{ + tSamplePoint *new_pt = MEM_callocN(sizeof(tSamplePoint), __func__); + copy_v3_v3(&new_pt->x, &pt->x); + new_pt->pressure = pt->pressure; + new_pt->strength = pt->strength; + new_pt->time = pt->time; + copy_v4_v4((float *)&new_pt->vertex_color, (float *)&pt->vert_color); + if (dvert != NULL) { + new_pt->totweight = dvert->totweight; + new_pt->dw = MEM_callocN(sizeof(MDeformWeight) * new_pt->totweight, __func__); + for (uint i = 0; i < new_pt->totweight; ++i) { + MDeformWeight *dw = &new_pt->dw[i]; + MDeformWeight *dw_from = &dvert->dw[i]; + dw->def_nr = dw_from->def_nr; + dw->weight = dw_from->weight; + } + } + return new_pt; +} + +/* Helper: creates a tSampleEdge from two tSamplePoints. Also calculates the length (squared) of + * the edge. */ +static tSampleEdge *new_sample_edge_from_sample_points(tSamplePoint *from, tSamplePoint *to) +{ + tSampleEdge *new_edge = MEM_callocN(sizeof(tSampleEdge), __func__); + new_edge->from = from; + new_edge->to = to; + new_edge->length_sq = len_squared_v3v3(&from->x, &to->x); + return new_edge; +} + +/** + * Subdivide the grease pencil stroke so the number of points is target_number. + * Does not change the shape of the stroke. The new points will be distributed as + * uniformly as possible by repeatedly subdividing the current longest edge. + * + * \param gps: The stroke to be up-sampled. + * \param target_number: The number of points the up-sampled stroke should have. + * \param select: Select/Deselect the stroke. + */ +void BKE_gpencil_stroke_uniform_subdivide(bGPdata *gpd, + bGPDstroke *gps, + const uint32_t target_number, + const bool select) +{ + /* Stroke needs at least two points and strictly less points than the target number. */ + if (gps == NULL || gps->totpoints < 2 || gps->totpoints >= target_number) { + return; + } + + const int totpoints = gps->totpoints; + const bool has_dverts = (gps->dvert != NULL); + const bool is_cyclic = (gps->flag & GP_STROKE_CYCLIC); + + ListBase points = {NULL, NULL}; + Heap *edges = BLI_heap_new(); + + /* Add all points into list. */ + for (uint32_t i = 0; i < totpoints; ++i) { + bGPDspoint *pt = &gps->points[i]; + MDeformVert *dvert = has_dverts ? &gps->dvert[i] : NULL; + tSamplePoint *sp = new_sample_point_from_gp_point(pt, dvert); + BLI_addtail(&points, sp); + } + + /* Iterate over edges and insert them into the heap. */ + for (tSamplePoint *pt = ((tSamplePoint *)points.first)->next; pt != NULL; pt = pt->next) { + tSampleEdge *se = new_sample_edge_from_sample_points(pt->prev, pt); + /* BLI_heap is a min-heap, but we need the largest key to be at the top, so we take the + * negative of the squared length. */ + BLI_heap_insert(edges, -(se->length_sq), se); + } + + if (is_cyclic) { + tSamplePoint *sp_first = points.first; + tSamplePoint *sp_last = points.last; + tSampleEdge *se = new_sample_edge_from_sample_points(sp_last, sp_first); + BLI_heap_insert(edges, -(se->length_sq), se); + } + + int num_points_needed = target_number - totpoints; + BLI_assert(num_points_needed > 0); + + while (num_points_needed > 0) { + tSampleEdge *se = BLI_heap_pop_min(edges); + tSamplePoint *sp = se->from; + tSamplePoint *sp_next = se->to; + + /* Subdivide the edge. */ + tSamplePoint *new_sp = MEM_callocN(sizeof(tSamplePoint), __func__); + interp_v3_v3v3(&new_sp->x, &sp->x, &sp_next->x, 0.5f); + new_sp->pressure = interpf(sp->pressure, sp_next->pressure, 0.5f); + new_sp->strength = interpf(sp->strength, sp_next->strength, 0.5f); + new_sp->time = interpf(sp->time, sp_next->time, 0.5f); + interp_v4_v4v4((float *)&new_sp->vertex_color, + (float *)&sp->vertex_color, + (float *)&sp_next->vertex_color, + 0.5f); + if (sp->dw && sp_next->dw) { + new_sp->totweight = MIN2(sp->totweight, sp_next->totweight); + new_sp->dw = MEM_callocN(sizeof(MDeformWeight) * new_sp->totweight, __func__); + for (uint32_t i = 0; i < new_sp->totweight; ++i) { + MDeformWeight *dw = &new_sp->dw[i]; + MDeformWeight *dw_from = &sp->dw[i]; + MDeformWeight *dw_to = &sp_next->dw[i]; + dw->def_nr = dw_from->def_nr; + dw->weight = interpf(dw_from->weight, dw_to->weight, 0.5f); + } + } + BLI_insertlinkafter(&points, sp, new_sp); + + tSampleEdge *se_prev = new_sample_edge_from_sample_points(sp, new_sp); + tSampleEdge *se_next = new_sample_edge_from_sample_points(new_sp, sp_next); + BLI_heap_insert(edges, -(se_prev->length_sq), se_prev); + BLI_heap_insert(edges, -(se_next->length_sq), se_next); + + MEM_freeN(se); + num_points_needed--; + } + + /* Edges are no longer needed. Heap is freed. */ + BLI_heap_free(edges, (HeapFreeFP)MEM_freeN); + + gps->totpoints = target_number; + gps->points = MEM_recallocN(gps->points, sizeof(bGPDspoint) * gps->totpoints); + if (has_dverts) { + gps->dvert = MEM_recallocN(gps->dvert, sizeof(MDeformVert) * gps->totpoints); + } + + /* Convert list back to stroke point array. */ + tSamplePoint *sp = points.first; + for (uint32_t i = 0; i < gps->totpoints && sp; ++i, sp = sp->next) { + bGPDspoint *pt = &gps->points[i]; + MDeformVert *dvert = &gps->dvert[i]; + + copy_v3_v3(&pt->x, &sp->x); + pt->pressure = sp->pressure; + pt->strength = sp->strength; + pt->time = sp->time; + copy_v4_v4((float *)&pt->vert_color, (float *)&sp->vertex_color); + + if (sp->dw) { + dvert->totweight = sp->totweight; + dvert->dw = MEM_callocN(sizeof(MDeformWeight) * dvert->totweight, __func__); + for (uint32_t j = 0; j < dvert->totweight; ++j) { + MDeformWeight *dw = &dvert->dw[j]; + MDeformWeight *dw_from = &sp->dw[j]; + dw->def_nr = dw_from->def_nr; + dw->weight = dw_from->weight; + } + } + if (select) { + pt->flag |= GP_SPOINT_SELECT; + } + } + + if (select) { + gps->flag |= GP_STROKE_SELECT; + } + + /* Free the sample points. Important to use the mutable loop here because we are erasing the list + * elements. */ + LISTBASE_FOREACH_MUTABLE (tSamplePoint *, temp, &points) { + if (temp->dw != NULL) { + MEM_freeN(temp->dw); + } + MEM_SAFE_FREE(temp); + } + + /* Update the geometry of the stroke. */ + BKE_gpencil_stroke_geometry_update(gpd, gps); +} + /** \} */ diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c index 7425a1a5f7a..1be2cba31b5 100644 --- a/source/blender/blenkernel/intern/gpencil_modifier.c +++ b/source/blender/blenkernel/intern/gpencil_modifier.c @@ -531,16 +531,16 @@ void BKE_gpencil_modifier_set_error(GpencilModifierData *md, const char *_format } /** - * Check whether given modifier is local when the object is a library override. + * Check whether given modifier is not local (i.e. from linked data) when the object is a library + * override. * - * \param gmd May be NULL, in which case we consider it as a non-local modifier case. - * - * \note This check is only valid for a liboverride data-block, it always return \a true otherwise. + * \param gmd: May be NULL, in which case we consider it as a non-local modifier case. */ -bool BKE_gpencil_modifier_is_local_in_liboverride(const Object *ob, const GpencilModifierData *gmd) +bool BKE_gpencil_modifier_is_nonlocal_in_liboverride(const Object *ob, + const GpencilModifierData *gmd) { - return (!ID_IS_OVERRIDE_LIBRARY(ob) || - (gmd != NULL && (gmd->flag & eGpencilModifierFlag_OverrideLibrary_Local) != 0)); + return (ID_IS_OVERRIDE_LIBRARY(ob) && + (gmd == NULL || (gmd->flag & eGpencilModifierFlag_OverrideLibrary_Local) == 0)); } /** diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.cc index eec9013d067..fbf69357478 100644 --- a/source/blender/blenkernel/intern/icons.c +++ b/source/blender/blenkernel/intern/icons.cc @@ -1,4 +1,4 @@ -/* +/* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 @@ -21,9 +21,10 @@ * \ingroup bke */ -#include <math.h> -#include <stdlib.h> -#include <string.h> +#include <cmath> +#include <cstdlib> +#include <cstring> +#include <mutex> #include "CLG_log.h" @@ -46,6 +47,7 @@ #include "BLI_string.h" #include "BLI_threads.h" #include "BLI_utildefines.h" +#include "BLI_vector.hh" #include "BKE_global.h" /* only for G.background test */ #include "BKE_icons.h" @@ -61,6 +63,8 @@ #include "BLO_read_write.h" +#include "atomic_ops.h" + /** * Only allow non-managed icons to be removed (by Python for eg). * Previews & ID's have their own functions to remove icons. @@ -73,28 +77,35 @@ enum { static CLG_LogRef LOG = {"bke.icons"}; -static GHash *gIcons = NULL; +/* Protected by gIconMutex. */ +static GHash *gIcons = nullptr; +/* Protected by gIconMutex. */ static int gNextIconId = 1; +/* Protected by gIconMutex. */ static int gFirstIconId = 1; -static GHash *gCachedPreviews = NULL; +std::mutex gIconMutex; + +/* Not mutex-protected! */ +static GHash *gCachedPreviews = nullptr; /* Queue of icons for deferred deletion. */ typedef struct DeferredIconDeleteNode { struct DeferredIconDeleteNode *next; int icon_id; } DeferredIconDeleteNode; +/* Protected by gIconMutex. */ static LockfreeLinkList g_icon_delete_queue; static void icon_free(void *val) { - Icon *icon = val; + Icon *icon = (Icon *)val; if (icon) { if (icon->obj_type == ICON_DATA_GEOM) { - struct Icon_Geom *obj = icon->obj; + struct Icon_Geom *obj = (struct Icon_Geom *)icon->obj; if (obj->mem) { /* coords & colors are part of this memory. */ MEM_freeN((void *)obj->mem); @@ -121,6 +132,12 @@ static void icon_free_data(int icon_id, Icon *icon) if (icon->obj_type == ICON_DATA_ID) { ((ID *)(icon->obj))->icon_id = 0; } + else if (icon->obj_type == ICON_DATA_IMBUF) { + ImBuf *imbuf = (ImBuf *)icon->obj; + if (imbuf) { + IMB_freeImBuf(imbuf); + } + } else if (icon->obj_type == ICON_DATA_PREVIEW) { ((PreviewImage *)(icon->obj))->icon_id = 0; } @@ -131,8 +148,8 @@ static void icon_free_data(int icon_id, Icon *icon) ((struct Icon_Geom *)(icon->obj))->icon_id = 0; } else if (icon->obj_type == ICON_DATA_STUDIOLIGHT) { - StudioLight *sl = icon->obj; - if (sl != NULL) { + StudioLight *sl = (StudioLight *)icon->obj; + if (sl != nullptr) { BKE_studiolight_unset_icon_id(sl, icon_id); } } @@ -141,19 +158,27 @@ static void icon_free_data(int icon_id, Icon *icon) } } +static Icon *icon_ghash_lookup(int icon_id) +{ + std::scoped_lock lock(gIconMutex); + return (Icon *)BLI_ghash_lookup(gIcons, POINTER_FROM_INT(icon_id)); +} + /* create an id for a new icon and make sure that ids from deleted icons get reused * after the integer number range is used up */ -static int get_next_free_id(void) +static int get_next_free_id() { - BLI_assert(BLI_thread_is_main()); + std::scoped_lock lock(gIconMutex); int startId = gFirstIconId; /* if we haven't used up the int number range, we just return the next int */ if (gNextIconId >= gFirstIconId) { - return gNextIconId++; + int next_id = gNextIconId++; + return next_id; } - /* now we try to find the smallest icon id not stored in the gIcons hash */ + /* Now we try to find the smallest icon id not stored in the gIcons hash. + * Don't use icon_ghash_lookup here, it would lock recursively (dead-lock). */ while (BLI_ghash_lookup(gIcons, POINTER_FROM_INT(startId)) && startId >= gFirstIconId) { startId++; } @@ -189,13 +214,13 @@ void BKE_icons_free(void) BLI_assert(BLI_thread_is_main()); if (gIcons) { - BLI_ghash_free(gIcons, NULL, icon_free); - gIcons = NULL; + BLI_ghash_free(gIcons, nullptr, icon_free); + gIcons = nullptr; } if (gCachedPreviews) { BLI_ghash_free(gCachedPreviews, MEM_freeN, BKE_previewimg_freefunc); - gCachedPreviews = NULL; + gCachedPreviews = nullptr; } BLI_linklist_lockfree_free(&g_icon_delete_queue, MEM_freeN); @@ -203,20 +228,21 @@ void BKE_icons_free(void) void BKE_icons_deferred_free(void) { - BLI_assert(BLI_thread_is_main()); + std::scoped_lock lock(gIconMutex); for (DeferredIconDeleteNode *node = (DeferredIconDeleteNode *)BLI_linklist_lockfree_begin(&g_icon_delete_queue); - node != NULL; + node != nullptr; node = node->next) { - BLI_ghash_remove(gIcons, POINTER_FROM_INT(node->icon_id), NULL, icon_free); + BLI_ghash_remove(gIcons, POINTER_FROM_INT(node->icon_id), nullptr, icon_free); } BLI_linklist_lockfree_clear(&g_icon_delete_queue, MEM_freeN); } static PreviewImage *previewimg_create_ex(size_t deferred_data_size) { - PreviewImage *prv_img = MEM_mallocN(sizeof(PreviewImage) + deferred_data_size, "img_prv"); + PreviewImage *prv_img = (PreviewImage *)MEM_mallocN(sizeof(PreviewImage) + deferred_data_size, + "img_prv"); memset(prv_img, 0, sizeof(*prv_img)); /* leave deferred data dirty */ if (deferred_data_size) { @@ -224,12 +250,26 @@ static PreviewImage *previewimg_create_ex(size_t deferred_data_size) } for (int i = 0; i < NUM_ICON_SIZES; i++) { - prv_img->flag[i] |= PRV_CHANGED; + prv_img->flag[i] |= (PRV_CHANGED | PRV_UNFINISHED); prv_img->changed_timestamp[i] = 0; } return prv_img; } +static PreviewImage *previewimg_deferred_create(const char *path, int source) +{ + /* We pack needed data for lazy loading (source type, in a single char, and path). */ + const size_t deferred_data_size = strlen(path) + 2; + char *deferred_data; + + PreviewImage *prv = previewimg_create_ex(deferred_data_size); + deferred_data = (char *)PRV_DEFERRED_DATA(prv); + deferred_data[0] = source; + memcpy(&deferred_data[1], path, deferred_data_size - 1); + + return prv; +} + PreviewImage *BKE_previewimg_create(void) { return previewimg_create_ex(0); @@ -256,7 +296,7 @@ void BKE_previewimg_free(PreviewImage **prv) { if (prv && (*prv)) { BKE_previewimg_freefunc(*prv); - *prv = NULL; + *prv = nullptr; } } @@ -267,7 +307,7 @@ void BKE_previewimg_clear_single(struct PreviewImage *prv, enum eIconSizes size) GPU_texture_free(prv->gputexture[size]); } prv->h[size] = prv->w[size] = 0; - prv->flag[size] |= PRV_CHANGED; + prv->flag[size] |= (PRV_CHANGED | PRV_UNFINISHED); prv->flag[size] &= ~PRV_USER_EDITED; prv->changed_timestamp[size] = 0; } @@ -275,21 +315,21 @@ void BKE_previewimg_clear_single(struct PreviewImage *prv, enum eIconSizes size) void BKE_previewimg_clear(struct PreviewImage *prv) { for (int i = 0; i < NUM_ICON_SIZES; i++) { - BKE_previewimg_clear_single(prv, i); + BKE_previewimg_clear_single(prv, (eIconSizes)i); } } PreviewImage *BKE_previewimg_copy(const PreviewImage *prv) { - PreviewImage *prv_img = NULL; + PreviewImage *prv_img = nullptr; if (prv) { - prv_img = MEM_dupallocN(prv); + prv_img = (PreviewImage *)MEM_dupallocN(prv); for (int i = 0; i < NUM_ICON_SIZES; i++) { if (prv->rect[i]) { - prv_img->rect[i] = MEM_dupallocN(prv->rect[i]); + prv_img->rect[i] = (uint *)MEM_dupallocN(prv->rect[i]); } - prv_img->gputexture[i] = NULL; + prv_img->gputexture[i] = nullptr; } } return prv_img; @@ -305,7 +345,7 @@ void BKE_previewimg_id_copy(ID *new_id, const ID *old_id) PreviewImage **new_prv_p = BKE_previewimg_id_get_p(new_id); if (old_prv_p && *old_prv_p) { - BLI_assert(new_prv_p != NULL && ELEM(*new_prv_p, NULL, *old_prv_p)); + BLI_assert(new_prv_p != nullptr && ELEM(*new_prv_p, nullptr, *old_prv_p)); // const int new_icon_id = get_next_free_id(); // if (new_icon_id == 0) { @@ -339,7 +379,13 @@ PreviewImage **BKE_previewimg_id_get_p(const ID *id) break; } - return NULL; + return nullptr; +} + +PreviewImage *BKE_previewimg_id_get(const ID *id) +{ + PreviewImage **prv_p = BKE_previewimg_id_get_p(id); + return prv_p ? *prv_p : nullptr; } void BKE_previewimg_id_free(ID *id) @@ -355,18 +401,60 @@ PreviewImage *BKE_previewimg_id_ensure(ID *id) PreviewImage **prv_p = BKE_previewimg_id_get_p(id); if (prv_p) { - if (*prv_p == NULL) { + if (*prv_p == nullptr) { *prv_p = BKE_previewimg_create(); } return *prv_p; } - return NULL; + return nullptr; +} + +void BKE_previewimg_id_custom_set(ID *id, const char *path) +{ + PreviewImage **prv = BKE_previewimg_id_get_p(id); + + /* Thumbnail previews must use the deferred pipeline. But we force them to be immediately + * generated here still. */ + + if (*prv) { + BKE_previewimg_deferred_release(*prv); + } + *prv = previewimg_deferred_create(path, THB_SOURCE_IMAGE); + + /* Can't lazy-render the preview on access. ID previews are saved to files and we want them to be + * there in time. Not only if something happened to have accessed it meanwhile. */ + for (int i = 0; i < NUM_ICON_SIZES; i++) { + BKE_previewimg_ensure(*prv, i); + /* Prevent auto-updates. */ + (*prv)->flag[i] |= PRV_USER_EDITED; + } +} + +bool BKE_previewimg_id_supports_jobs(const ID *id) +{ + return ELEM(GS(id->name), ID_OB, ID_MA, ID_TE, ID_LA, ID_WO, ID_IM, ID_BR); +} + +void BKE_previewimg_deferred_release(PreviewImage *prv) +{ + if (prv) { + if (prv->tag & PRV_TAG_DEFFERED_RENDERING) { + /* We cannot delete the preview while it is being loaded in another thread... */ + prv->tag |= PRV_TAG_DEFFERED_DELETE; + return; + } + if (prv->icon_id) { + BKE_icon_delete(prv->icon_id); + } + BKE_previewimg_freefunc(prv); + } } PreviewImage *BKE_previewimg_cached_get(const char *name) { - return BLI_ghash_lookup(gCachedPreviews, name); + BLI_assert(BLI_thread_is_main()); + return (PreviewImage *)BLI_ghash_lookup(gCachedPreviews, name); } /** @@ -374,14 +462,16 @@ PreviewImage *BKE_previewimg_cached_get(const char *name) */ PreviewImage *BKE_previewimg_cached_ensure(const char *name) { - PreviewImage *prv = NULL; + BLI_assert(BLI_thread_is_main()); + + PreviewImage *prv = nullptr; void **key_p, **prv_p; if (!BLI_ghash_ensure_p_ex(gCachedPreviews, name, &key_p, &prv_p)) { *key_p = BLI_strdup(name); *prv_p = BKE_previewimg_create(); } - prv = *prv_p; + prv = *(PreviewImage **)prv_p; BLI_assert(prv); return prv; @@ -389,24 +479,27 @@ PreviewImage *BKE_previewimg_cached_ensure(const char *name) /** * Generate a PreviewImage from given file path, using thumbnails management, if not yet existing. + * Does not actually generate the preview, #BKE_previewimg_ensure() must be called for that. */ PreviewImage *BKE_previewimg_cached_thumbnail_read(const char *name, const char *path, const int source, bool force_update) { - PreviewImage *prv = NULL; + BLI_assert(BLI_thread_is_main()); + + PreviewImage *prv = nullptr; void **prv_p; prv_p = BLI_ghash_lookup_p(gCachedPreviews, name); if (prv_p) { - prv = *prv_p; + prv = *(PreviewImage **)prv_p; BLI_assert(prv); } if (prv && force_update) { - const char *prv_deferred_data = PRV_DEFERRED_DATA(prv); + const char *prv_deferred_data = (char *)PRV_DEFERRED_DATA(prv); if (((int)prv_deferred_data[0] == source) && STREQ(&prv_deferred_data[1], path)) { /* If same path, no need to re-allocate preview, just clear it up. */ BKE_previewimg_clear(prv); @@ -417,15 +510,7 @@ PreviewImage *BKE_previewimg_cached_thumbnail_read(const char *name, } if (!prv) { - /* We pack needed data for lazy loading (source type, in a single char, and path). */ - const size_t deferred_data_size = strlen(path) + 2; - char *deferred_data; - - prv = previewimg_create_ex(deferred_data_size); - deferred_data = PRV_DEFERRED_DATA(prv); - deferred_data[0] = source; - memcpy(&deferred_data[1], path, deferred_data_size - 1); - + prv = previewimg_deferred_create(path, source); force_update = true; } @@ -441,26 +526,13 @@ PreviewImage *BKE_previewimg_cached_thumbnail_read(const char *name, return prv; } -void BKE_previewimg_cached_release_pointer(PreviewImage *prv) -{ - if (prv) { - if (prv->tag & PRV_TAG_DEFFERED_RENDERING) { - /* We cannot delete the preview while it is being loaded in another thread... */ - prv->tag |= PRV_TAG_DEFFERED_DELETE; - return; - } - if (prv->icon_id) { - BKE_icon_delete(prv->icon_id); - } - BKE_previewimg_freefunc(prv); - } -} - void BKE_previewimg_cached_release(const char *name) { - PreviewImage *prv = BLI_ghash_popkey(gCachedPreviews, name, MEM_freeN); + BLI_assert(BLI_thread_is_main()); + + PreviewImage *prv = (PreviewImage *)BLI_ghash_popkey(gCachedPreviews, name, MEM_freeN); - BKE_previewimg_cached_release_pointer(prv); + BKE_previewimg_deferred_release(prv); } /** @@ -475,12 +547,12 @@ void BKE_previewimg_ensure(PreviewImage *prv, const int size) if (do_icon || do_preview) { ImBuf *thumb; - char *prv_deferred_data = PRV_DEFERRED_DATA(prv); + char *prv_deferred_data = (char *)PRV_DEFERRED_DATA(prv); int source = prv_deferred_data[0]; char *path = &prv_deferred_data[1]; int icon_w, icon_h; - thumb = IMB_thumb_manage(path, THB_LARGE, source); + thumb = IMB_thumb_manage(path, THB_LARGE, (ThumbSource)source); if (thumb) { /* PreviewImage assumes premultiplied alhpa... */ @@ -489,8 +561,8 @@ void BKE_previewimg_ensure(PreviewImage *prv, const int size) if (do_preview) { prv->w[ICON_SIZE_PREVIEW] = thumb->x; prv->h[ICON_SIZE_PREVIEW] = thumb->y; - prv->rect[ICON_SIZE_PREVIEW] = MEM_dupallocN(thumb->rect); - prv->flag[ICON_SIZE_PREVIEW] &= ~(PRV_CHANGED | PRV_USER_EDITED); + prv->rect[ICON_SIZE_PREVIEW] = (uint *)MEM_dupallocN(thumb->rect); + prv->flag[ICON_SIZE_PREVIEW] &= ~(PRV_CHANGED | PRV_USER_EDITED | PRV_UNFINISHED); } if (do_icon) { if (thumb->x > thumb->y) { @@ -508,8 +580,8 @@ void BKE_previewimg_ensure(PreviewImage *prv, const int size) IMB_scaleImBuf(thumb, icon_w, icon_h); prv->w[ICON_SIZE_ICON] = icon_w; prv->h[ICON_SIZE_ICON] = icon_h; - prv->rect[ICON_SIZE_ICON] = MEM_dupallocN(thumb->rect); - prv->flag[ICON_SIZE_ICON] &= ~(PRV_CHANGED | PRV_USER_EDITED); + prv->rect[ICON_SIZE_ICON] = (uint *)MEM_dupallocN(thumb->rect); + prv->flag[ICON_SIZE_ICON] &= ~(PRV_CHANGED | PRV_USER_EDITED | PRV_UNFINISHED); } IMB_freeImBuf(thumb); } @@ -517,13 +589,45 @@ void BKE_previewimg_ensure(PreviewImage *prv, const int size) } } +/** + * Create an #ImBuf holding a copy of the preview image buffer in \a prv. + * \note The returned image buffer has to be free'd (#IMB_freeImBuf()). + */ +ImBuf *BKE_previewimg_to_imbuf(PreviewImage *prv, const int size) +{ + const unsigned int w = prv->w[size]; + const unsigned int h = prv->h[size]; + const unsigned int *rect = prv->rect[size]; + + ImBuf *ima = nullptr; + + if (w > 0 && h > 0 && rect) { + /* first allocate imbuf for copying preview into it */ + ima = IMB_allocImBuf(w, h, 32, IB_rect); + memcpy(ima->rect, rect, w * h * sizeof(*ima->rect)); + } + + return ima; +} + +void BKE_previewimg_finish(PreviewImage *prv, const int size) +{ + /* Previews may be calculated on a thread. */ + atomic_fetch_and_and_int16(&prv->flag[size], ~PRV_UNFINISHED); +} + +bool BKE_previewimg_is_finished(const PreviewImage *prv, const int size) +{ + return (prv->flag[size] & PRV_UNFINISHED) == 0; +} + void BKE_previewimg_blend_write(BlendWriter *writer, const PreviewImage *prv) { /* Note we write previews also for undo steps. It takes up some memory, * but not doing so would causes all previews to be re-rendered after * undo which is too expensive. */ - if (prv == NULL) { + if (prv == nullptr) { return; } @@ -532,7 +636,7 @@ void BKE_previewimg_blend_write(BlendWriter *writer, const PreviewImage *prv) if (!(U.flag & USER_SAVE_PREVIEWS)) { prv_copy.w[1] = 0; prv_copy.h[1] = 0; - prv_copy.rect[1] = NULL; + prv_copy.rect[1] = nullptr; } BLO_write_struct_at_address(writer, PreviewImage, prv, &prv_copy); if (prv_copy.rect[0]) { @@ -545,7 +649,7 @@ void BKE_previewimg_blend_write(BlendWriter *writer, const PreviewImage *prv) void BKE_previewimg_blend_read(BlendDataReader *reader, PreviewImage *prv) { - if (prv == NULL) { + if (prv == nullptr) { return; } @@ -553,7 +657,18 @@ void BKE_previewimg_blend_read(BlendDataReader *reader, PreviewImage *prv) if (prv->rect[i]) { BLO_read_data_address(reader, &prv->rect[i]); } - prv->gputexture[i] = NULL; + prv->gputexture[i] = nullptr; + /* For now consider previews read from file as finished to not confuse File Browser preview + * loading. That could be smarter and check if there's a preview job running instead. + * If the preview is tagged as changed, it needs to be updated anyway, so don't remove the tag. + */ + if ((prv->flag[i] & PRV_CHANGED) == 0) { + BKE_previewimg_finish(prv, i); + } + else { + /* Only for old files that didn't write the flag . */ + prv->flag[i] |= PRV_UNFINISHED; + } } prv->icon_id = 0; prv->tag = 0; @@ -561,15 +676,13 @@ void BKE_previewimg_blend_read(BlendDataReader *reader, PreviewImage *prv) void BKE_icon_changed(const int icon_id) { - BLI_assert(BLI_thread_is_main()); - - Icon *icon = NULL; + Icon *icon = nullptr; if (!icon_id || G.background) { return; } - icon = BLI_ghash_lookup(gIcons, POINTER_FROM_INT(icon_id)); + icon = icon_ghash_lookup(icon_id); if (icon) { /* We *only* expect ID-tied icons here, not non-ID icon/preview! */ @@ -584,7 +697,7 @@ void BKE_icon_changed(const int icon_id) /* If we have previews, they all are now invalid changed. */ if (p_prv && *p_prv) { for (int i = 0; i < NUM_ICON_SIZES; i++) { - (*p_prv)->flag[i] |= PRV_CHANGED; + (*p_prv)->flag[i] |= (PRV_CHANGED | PRV_UNFINISHED); (*p_prv)->changed_timestamp[i]++; } } @@ -593,7 +706,7 @@ void BKE_icon_changed(const int icon_id) static Icon *icon_create(int icon_id, int obj_type, void *obj) { - Icon *new_icon = MEM_mallocN(sizeof(Icon), __func__); + Icon *new_icon = (Icon *)MEM_mallocN(sizeof(Icon), __func__); new_icon->obj_type = obj_type; new_icon->obj = obj; @@ -601,10 +714,13 @@ static Icon *icon_create(int icon_id, int obj_type, void *obj) new_icon->flag = 0; /* next two lines make sure image gets created */ - new_icon->drawinfo = NULL; - new_icon->drawinfo_free = NULL; + new_icon->drawinfo = nullptr; + new_icon->drawinfo_free = nullptr; - BLI_ghash_insert(gIcons, POINTER_FROM_INT(icon_id), new_icon); + { + std::scoped_lock lock(gIconMutex); + BLI_ghash_insert(gIcons, POINTER_FROM_INT(icon_id), new_icon); + } return new_icon; } @@ -731,17 +847,47 @@ int BKE_icon_preview_ensure(ID *id, PreviewImage *preview) return preview->icon_id; } +/** + * Create an icon as owner or \a ibuf. The icon-ID is not stored in \a ibuf, it needs to be stored + * separately. + * \note Transforms ownership of \a ibuf to the newly created icon. + */ +int BKE_icon_imbuf_create(ImBuf *ibuf) +{ + int icon_id = get_next_free_id(); + + Icon *icon = icon_create(icon_id, ICON_DATA_IMBUF, ibuf); + icon->flag = ICON_FLAG_MANAGED; + + return icon_id; +} + +ImBuf *BKE_icon_imbuf_get_buffer(int icon_id) +{ + Icon *icon = icon_ghash_lookup(icon_id); + if (!icon) { + CLOG_ERROR(&LOG, "no icon for icon ID: %d", icon_id); + return nullptr; + } + if (icon->obj_type != ICON_DATA_IMBUF) { + CLOG_ERROR(&LOG, "icon ID does not refer to an imbuf icon: %d", icon_id); + return nullptr; + } + + return (ImBuf *)icon->obj; +} + Icon *BKE_icon_get(const int icon_id) { BLI_assert(BLI_thread_is_main()); - Icon *icon = NULL; + Icon *icon = nullptr; - icon = BLI_ghash_lookup(gIcons, POINTER_FROM_INT(icon_id)); + icon = icon_ghash_lookup(icon_id); if (!icon) { CLOG_ERROR(&LOG, "no icon for icon ID: %d", icon_id); - return NULL; + return nullptr; } return icon; @@ -749,10 +895,9 @@ Icon *BKE_icon_get(const int icon_id) void BKE_icon_set(const int icon_id, struct Icon *icon) { - BLI_assert(BLI_thread_is_main()); - void **val_p; + std::scoped_lock lock(gIconMutex); if (BLI_ghash_ensure_p(gIcons, POINTER_FROM_INT(icon_id), &val_p)) { CLOG_ERROR(&LOG, "icon already set: %d", icon_id); return; @@ -763,8 +908,10 @@ void BKE_icon_set(const int icon_id, struct Icon *icon) static void icon_add_to_deferred_delete_queue(int icon_id) { - DeferredIconDeleteNode *node = MEM_mallocN(sizeof(DeferredIconDeleteNode), __func__); + DeferredIconDeleteNode *node = (DeferredIconDeleteNode *)MEM_mallocN( + sizeof(DeferredIconDeleteNode), __func__); node->icon_id = icon_id; + /* Doesn't need lock. */ BLI_linklist_lockfree_insert(&g_icon_delete_queue, (LockfreeLinkNode *)node); } @@ -782,7 +929,8 @@ void BKE_icon_id_delete(struct ID *id) } BKE_icons_deferred_free(); - BLI_ghash_remove(gIcons, POINTER_FROM_INT(icon_id), NULL, icon_free); + std::scoped_lock lock(gIconMutex); + BLI_ghash_remove(gIcons, POINTER_FROM_INT(icon_id), nullptr, icon_free); } /** @@ -795,8 +943,8 @@ bool BKE_icon_delete(const int icon_id) return false; } - Icon *icon = BLI_ghash_popkey(gIcons, POINTER_FROM_INT(icon_id), NULL); - if (icon) { + std::scoped_lock lock(gIconMutex); + if (Icon *icon = (Icon *)BLI_ghash_popkey(gIcons, POINTER_FROM_INT(icon_id), nullptr)) { icon_free_data(icon_id, icon); icon_free(icon); return true; @@ -812,7 +960,9 @@ bool BKE_icon_delete_unmanaged(const int icon_id) return false; } - Icon *icon = BLI_ghash_popkey(gIcons, POINTER_FROM_INT(icon_id), NULL); + std::scoped_lock lock(gIconMutex); + + Icon *icon = (Icon *)BLI_ghash_popkey(gIcons, POINTER_FROM_INT(icon_id), nullptr); if (icon) { if (UNLIKELY(icon->flag & ICON_FLAG_MANAGED)) { BLI_ghash_insert(gIcons, POINTER_FROM_INT(icon_id), icon); @@ -847,52 +997,52 @@ int BKE_icon_geom_ensure(struct Icon_Geom *geom) return geom->icon_id; } -struct Icon_Geom *BKE_icon_geom_from_memory(const uchar *data, size_t data_len) +struct Icon_Geom *BKE_icon_geom_from_memory(uchar *data, size_t data_len) { BLI_assert(BLI_thread_is_main()); if (data_len <= 8) { - goto fail; + return nullptr; } + /* Wrapper for RAII early exit cleanups. */ + std::unique_ptr<uchar> data_wrapper(std::move(data)); + /* Skip the header. */ data_len -= 8; const int div = 3 * 2 * 3; const int coords_len = data_len / div; if (coords_len * div != data_len) { - goto fail; + return nullptr; } const uchar header[4] = {'V', 'C', 'O', 0}; - const uchar *p = data; + uchar *p = data_wrapper.get(); if (memcmp(p, header, ARRAY_SIZE(header)) != 0) { - goto fail; + return nullptr; } p += 4; - struct Icon_Geom *geom = MEM_mallocN(sizeof(*geom), __func__); + struct Icon_Geom *geom = (struct Icon_Geom *)MEM_mallocN(sizeof(*geom), __func__); geom->coords_range[0] = (int)*p++; geom->coords_range[1] = (int)*p++; /* x, y ignored for now */ p += 2; geom->coords_len = coords_len; - geom->coords = (void *)p; - geom->colors = (void *)(p + (data_len / 3)); + geom->coords = reinterpret_cast<decltype(geom->coords)>(p); + geom->colors = reinterpret_cast<decltype(geom->colors)>(p + (data_len / 3)); geom->icon_id = 0; - geom->mem = data; + /* Move buffer ownership to C buffer. */ + geom->mem = data_wrapper.release(); return geom; - -fail: - MEM_freeN((void *)data); - return NULL; } struct Icon_Geom *BKE_icon_geom_from_file(const char *filename) { BLI_assert(BLI_thread_is_main()); size_t data_len; - uchar *data = BLI_file_read_binary_as_mem(filename, 0, &data_len); - if (data == NULL) { - return NULL; + uchar *data = (uchar *)BLI_file_read_binary_as_mem(filename, 0, &data_len); + if (data == nullptr) { + return nullptr; } return BKE_icon_geom_from_memory(data, data_len); } diff --git a/source/blender/blenkernel/intern/idprop_utils.c b/source/blender/blenkernel/intern/idprop_utils.c index f8a1113f69b..433f0e97844 100644 --- a/source/blender/blenkernel/intern/idprop_utils.c +++ b/source/blender/blenkernel/intern/idprop_utils.c @@ -26,6 +26,8 @@ #include "BLI_string.h" #include "BLI_utildefines.h" +#include "DNA_ID.h" + #include "BKE_idprop.h" #include "BKE_idtype.h" diff --git a/source/blender/blenkernel/intern/idtype.c b/source/blender/blenkernel/intern/idtype.c index 44bf8f0e4db..1889d1c4eb0 100644 --- a/source/blender/blenkernel/intern/idtype.c +++ b/source/blender/blenkernel/intern/idtype.c @@ -36,6 +36,7 @@ #include "BLT_translation.h" #include "DNA_ID.h" +#include "DNA_collection_types.h" #include "DNA_node_types.h" #include "DNA_scene_types.h" diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index cd2ed32cd4f..ab57d14d2cf 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -54,6 +54,7 @@ #include "DNA_camera_types.h" #include "DNA_defaults.h" #include "DNA_light_types.h" +#include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" @@ -92,7 +93,7 @@ #include "RE_pipeline.h" -#include "SEQ_sequencer.h" /* seq_foreground_frame_get() */ +#include "SEQ_utils.h" /* SEQ_get_topmost_sequence() */ #include "GPU_texture.h" @@ -189,6 +190,7 @@ static void image_free_data(ID *id) BKE_previewimg_free(&image->preview); BLI_freelistN(&image->tiles); + BLI_freelistN(&image->gpu_refresh_areas); } static void image_foreach_cache(ID *id, @@ -225,14 +227,21 @@ static void image_foreach_cache(ID *id, static void image_blend_write(BlendWriter *writer, ID *id, const void *id_address) { Image *ima = (Image *)id; - if (ima->id.us > 0 || BLO_write_is_undo(writer)) { + const bool is_undo = BLO_write_is_undo(writer); + if (ima->id.us > 0 || is_undo) { ImagePackedFile *imapf; - /* Some trickery to keep forward compatibility of packed images. */ BLI_assert(ima->packedfile == NULL); - if (ima->packedfiles.first != NULL) { - imapf = ima->packedfiles.first; - ima->packedfile = imapf->packedfile; + /* Do not store packed files in case this is a library override ID. */ + if (ID_IS_OVERRIDE_LIBRARY(ima) && !is_undo) { + BLI_listbase_clear(&ima->packedfiles); + } + else { + /* Some trickery to keep forward compatibility of packed images. */ + if (ima->packedfiles.first != NULL) { + imapf = ima->packedfiles.first; + ima->packedfile = imapf->packedfile; + } } /* write LibData */ @@ -290,6 +299,8 @@ static void image_blend_read_data(BlendDataReader *reader, ID *id) LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) { tile->ok = IMA_OK; } + ima->gpuflag = 0; + BLI_listbase_clear(&ima->gpu_refresh_areas); } static void image_blend_read_lib(BlendLibReader *UNUSED(reader), ID *id) @@ -2046,7 +2057,7 @@ static void stampdata( } if (use_dynamic && scene->r.stamp & R_STAMP_SEQSTRIP) { - const Sequence *seq = BKE_sequencer_foreground_frame_get(scene, scene->r.cfra); + const Sequence *seq = SEQ_get_topmost_sequence(scene, scene->r.cfra); if (seq) { STRNCPY(text, seq->name + 2); @@ -3889,6 +3900,7 @@ RenderResult *BKE_image_acquire_renderresult(Scene *scene, Image *ima) } else { rr = BKE_image_get_renderslot(ima, ima->render_slot)->render; + ima->gpuflag |= IMA_GPU_REFRESH; } /* set proper views */ diff --git a/source/blender/blenkernel/intern/image_gpu.c b/source/blender/blenkernel/intern/image_gpu.c index 9ed233ab34c..05aa3c89a84 100644 --- a/source/blender/blenkernel/intern/image_gpu.c +++ b/source/blender/blenkernel/intern/image_gpu.c @@ -23,6 +23,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_bitmap.h" #include "BLI_boxpack_2d.h" #include "BLI_linklist.h" #include "BLI_listbase.h" @@ -48,6 +49,16 @@ /* Prototypes. */ static void gpu_free_unused_buffers(void); static void image_free_gpu(Image *ima, const bool immediate); +static void image_update_gputexture_ex( + Image *ima, ImageTile *tile, ImBuf *ibuf, int x, int y, int w, int h); + +/* Internal structs. */ +#define IMA_PARTIAL_REFRESH_TILE_SIZE 256 +typedef struct ImagePartialRefresh { + struct ImagePartialRefresh *next, *prev; + int tile_x; + int tile_y; +} ImagePartialRefresh; /* Is the alpha of the `GPUTexture` for a given image/ibuf premultiplied. */ bool BKE_image_has_gpu_texture_premultiplied_alpha(Image *image, ImBuf *ibuf) @@ -62,7 +73,7 @@ bool BKE_image_has_gpu_texture_premultiplied_alpha(Image *image, ImBuf *ibuf) return ibuf->rect_float != NULL; } } - else if (ibuf) { + if (ibuf) { if (ibuf->rect_float) { return image ? (image->alpha_mode != IMA_ALPHA_STRAIGHT) : false; } @@ -299,19 +310,35 @@ static GPUTexture *image_get_gpu_texture(Image *ima, * the current `pass` and `layer` should be 0. */ short requested_pass = iuser ? iuser->pass : 0; short requested_layer = iuser ? iuser->layer : 0; - short requested_slot = ima->render_slot; - if (ima->gpu_pass != requested_pass || ima->gpu_layer != requested_layer || - ima->gpu_slot != requested_slot) { + if (ima->gpu_pass != requested_pass || ima->gpu_layer != requested_layer) { ima->gpu_pass = requested_pass; ima->gpu_layer = requested_layer; - ima->gpu_slot = requested_slot; ima->gpuflag |= IMA_GPU_REFRESH; } - /* currently, gpu refresh tagging is used by ima sequences */ - if (ima->gpuflag & IMA_GPU_REFRESH) { + /* Check if image has been updated and tagged to be updated (full or partial). */ + ImageTile *tile = BKE_image_get_tile(ima, 0); + if (((ima->gpuflag & IMA_GPU_REFRESH) != 0) || + ((ibuf == NULL || tile == NULL || !tile->ok) && + ((ima->gpuflag & IMA_GPU_PARTIAL_REFRESH) != 0))) { image_free_gpu(ima, true); - ima->gpuflag &= ~IMA_GPU_REFRESH; + BLI_freelistN(&ima->gpu_refresh_areas); + ima->gpuflag &= ~(IMA_GPU_REFRESH | IMA_GPU_PARTIAL_REFRESH); + } + else if (ima->gpuflag & IMA_GPU_PARTIAL_REFRESH) { + BLI_assert(ibuf); + BLI_assert(tile && tile->ok); + ImagePartialRefresh *refresh_area; + while ((refresh_area = BLI_pophead(&ima->gpu_refresh_areas))) { + const int tile_offset_x = refresh_area->tile_x * IMA_PARTIAL_REFRESH_TILE_SIZE; + const int tile_offset_y = refresh_area->tile_y * IMA_PARTIAL_REFRESH_TILE_SIZE; + const int tile_width = MIN2(IMA_PARTIAL_REFRESH_TILE_SIZE, ibuf->x - tile_offset_x); + const int tile_height = MIN2(IMA_PARTIAL_REFRESH_TILE_SIZE, ibuf->y - tile_offset_y); + image_update_gputexture_ex( + ima, tile, ibuf, tile_offset_x, tile_offset_y, tile_width, tile_height); + MEM_freeN(refresh_area); + } + ima->gpuflag &= ~IMA_GPU_PARTIAL_REFRESH; } /* Tag as in active use for garbage collector. */ @@ -328,7 +355,6 @@ static GPUTexture *image_get_gpu_texture(Image *ima, /* Check if we have a valid image. If not, we return a dummy * texture with zero bind-code so we don't keep trying. */ - ImageTile *tile = BKE_image_get_tile(ima, 0); if (tile == NULL || tile->ok == 0) { *tex = image_gpu_texture_error_create(textarget); return *tex; @@ -590,8 +616,8 @@ static void gpu_texture_update_scaled(GPUTexture *tex, } else { /* Partial update with scaling. */ - int limit_w = smaller_power_of_2_limit(full_w); - int limit_h = smaller_power_of_2_limit(full_h); + int limit_w = GPU_texture_width(tex); + int limit_h = GPU_texture_height(tex); ibuf = update_do_scale(rect, rect_float, &x, &y, &w, &h, limit_w, limit_h, full_w, full_h); } @@ -643,7 +669,7 @@ static void gpu_texture_update_from_ibuf( scaled = (ibuf->x != tilesize[0]) || (ibuf->y != tilesize[1]); } else { - scaled = is_over_resolution_limit(ibuf->x, ibuf->y); + scaled = (GPU_texture_width(tex) != ibuf->x) || (GPU_texture_height(tex) != ibuf->y); } if (scaled) { @@ -746,6 +772,22 @@ static void gpu_texture_update_from_ibuf( GPU_texture_unbind(tex); } +static void image_update_gputexture_ex( + Image *ima, ImageTile *tile, ImBuf *ibuf, int x, int y, int w, int h) +{ + GPUTexture *tex = ima->gputexture[TEXTARGET_2D][0]; + /* Check if we need to update the main gputexture. */ + if (tex != NULL && tile == ima->tiles.first) { + gpu_texture_update_from_ibuf(tex, ima, ibuf, NULL, x, y, w, h); + } + + /* Check if we need to update the array gputexture. */ + tex = ima->gputexture[TEXTARGET_2D_ARRAY][0]; + if (tex != NULL) { + gpu_texture_update_from_ibuf(tex, ima, ibuf, tile, x, y, w, h); + } +} + /* Partial update of texture for texture painting. This is often much * quicker than fully updating the texture for high resolution images. */ void BKE_image_update_gputexture(Image *ima, ImageUser *iuser, int x, int y, int w, int h) @@ -757,20 +799,84 @@ void BKE_image_update_gputexture(Image *ima, ImageUser *iuser, int x, int y, int /* Full reload of texture. */ BKE_image_free_gputextures(ima); } + image_update_gputexture_ex(ima, tile, ibuf, x, y, w, h); + BKE_image_release_ibuf(ima, ibuf, NULL); +} - GPUTexture *tex = ima->gputexture[TEXTARGET_2D][0]; - /* Check if we need to update the main gputexture. */ - if (tex != NULL && tile == ima->tiles.first) { - gpu_texture_update_from_ibuf(tex, ima, ibuf, NULL, x, y, w, h); +/* Mark areas on the GPUTexture that needs to be updated. The areas are marked in chunks. + * The next time the GPUTexture is used these tiles will be refreshes. This saves time + * when writing to the same place multiple times This happens for during foreground + * rendering. */ +void BKE_image_update_gputexture_delayed( + struct Image *ima, struct ImBuf *ibuf, int x, int y, int w, int h) +{ + /* Check for full refresh. */ + if (ibuf && x == 0 && y == 0 && w == ibuf->x && h == ibuf->y) { + ima->gpuflag |= IMA_GPU_REFRESH; + } + /* Check if we can promote partial refresh to a full refresh. */ + if ((ima->gpuflag & (IMA_GPU_REFRESH | IMA_GPU_PARTIAL_REFRESH)) == + (IMA_GPU_REFRESH | IMA_GPU_PARTIAL_REFRESH)) { + ima->gpuflag &= ~IMA_GPU_PARTIAL_REFRESH; + BLI_freelistN(&ima->gpu_refresh_areas); + } + /* Image is already marked for complete refresh. */ + if (ima->gpuflag & IMA_GPU_REFRESH) { + return; } - /* Check if we need to update the array gputexture. */ - tex = ima->gputexture[TEXTARGET_2D_ARRAY][0]; - if (tex != NULL) { - gpu_texture_update_from_ibuf(tex, ima, ibuf, tile, x, y, w, h); + /* Schedule the tiles that covers the requested area. */ + const int start_tile_x = x / IMA_PARTIAL_REFRESH_TILE_SIZE; + const int start_tile_y = y / IMA_PARTIAL_REFRESH_TILE_SIZE; + const int end_tile_x = (x + w) / IMA_PARTIAL_REFRESH_TILE_SIZE; + const int end_tile_y = (y + h) / IMA_PARTIAL_REFRESH_TILE_SIZE; + const int num_tiles_x = (end_tile_x + 1) - (start_tile_x); + const int num_tiles_y = (end_tile_y + 1) - (start_tile_y); + const int num_tiles = num_tiles_x * num_tiles_y; + const bool allocate_on_heap = BLI_BITMAP_SIZE(num_tiles) > 16; + BLI_bitmap *requested_tiles = NULL; + if (allocate_on_heap) { + requested_tiles = BLI_BITMAP_NEW(num_tiles, __func__); + } + else { + requested_tiles = BLI_BITMAP_NEW_ALLOCA(num_tiles); } - BKE_image_release_ibuf(ima, ibuf, NULL); + /* Mark the tiles that have already been requested. They don't need to be requested again. */ + int num_tiles_not_scheduled = num_tiles; + LISTBASE_FOREACH (ImagePartialRefresh *, area, &ima->gpu_refresh_areas) { + if (area->tile_x < start_tile_x || area->tile_x > end_tile_x || area->tile_y < start_tile_y || + area->tile_y > end_tile_y) { + continue; + } + int requested_tile_index = (area->tile_x - start_tile_x) + + (area->tile_y - start_tile_y) * num_tiles_x; + BLI_BITMAP_ENABLE(requested_tiles, requested_tile_index); + num_tiles_not_scheduled--; + if (num_tiles_not_scheduled == 0) { + break; + } + } + + /* Schedule the tiles that aren't requested yet. */ + if (num_tiles_not_scheduled) { + int tile_index = 0; + for (int tile_y = start_tile_y; tile_y <= end_tile_y; tile_y++) { + for (int tile_x = start_tile_x; tile_x <= end_tile_x; tile_x++) { + if (!BLI_BITMAP_TEST_BOOL(requested_tiles, tile_index)) { + ImagePartialRefresh *area = MEM_mallocN(sizeof(ImagePartialRefresh), __func__); + area->tile_x = tile_x; + area->tile_y = tile_y; + BLI_addtail(&ima->gpu_refresh_areas, area); + } + tile_index++; + } + } + ima->gpuflag |= IMA_GPU_PARTIAL_REFRESH; + } + if (allocate_on_heap) { + MEM_freeN(requested_tiles); + } } /* these two functions are called on entering and exiting texture paint mode, diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c index 9696d920640..1ab6e61e20e 100644 --- a/source/blender/blenkernel/intern/ipo.c +++ b/source/blender/blenkernel/intern/ipo.c @@ -74,7 +74,7 @@ #include "MEM_guardedalloc.h" -#include "SEQ_sequencer.h" +#include "SEQ_iterator.h" #include "BLO_read_write.h" @@ -467,7 +467,9 @@ static char *shapekey_adrcodes_to_paths(ID *id, int adrcode, int *UNUSED(array_i /* setting that we alter is the "value" (i.e. keyblock.curval) */ if (kb) { /* Use the keyblock name, escaped, so that path lookups for this will work */ - BLI_snprintf(buf, sizeof(buf), "key_blocks[\"%s\"].value", kb->name); + char kb_name_esc[sizeof(kb->name) * 2]; + BLI_str_escape(kb_name_esc, kb->name, sizeof(kb_name_esc)); + BLI_snprintf(buf, sizeof(buf), "key_blocks[\"%s\"].value", kb_name_esc); } else { /* Fallback - Use the adrcode as index directly, so that this can be manually fixed */ @@ -1118,7 +1120,7 @@ static char *get_rna_access(ID *id, propname = "speed_fader"; break; case SEQ_FAC_OPACITY: - propname = "blend_opacity"; + propname = "blend_alpha"; break; } /* XXX this doesn't seem to be included anywhere in sequencer RNA... */ @@ -1160,7 +1162,12 @@ static char *get_rna_access(ID *id, /* note, strings are not escapted and they should be! */ if ((actname && actname[0]) && (constname && constname[0])) { /* Constraint in Pose-Channel */ - BLI_snprintf(buf, sizeof(buf), "pose.bones[\"%s\"].constraints[\"%s\"]", actname, constname); + char actname_esc[sizeof(((bActionChannel *)NULL)->name) * 2]; + char constname_esc[sizeof(((bConstraint *)NULL)->name) * 2]; + BLI_str_escape(actname_esc, actname, sizeof(actname_esc)); + BLI_str_escape(constname_esc, constname, sizeof(constname_esc)); + BLI_snprintf( + buf, sizeof(buf), "pose.bones[\"%s\"].constraints[\"%s\"]", actname_esc, constname_esc); } else if (actname && actname[0]) { if ((blocktype == ID_OB) && STREQ(actname, "Object")) { @@ -1174,16 +1181,22 @@ static char *get_rna_access(ID *id, } else { /* Pose-Channel */ - BLI_snprintf(buf, sizeof(buf), "pose.bones[\"%s\"]", actname); + char actname_esc[sizeof(((bActionChannel *)NULL)->name) * 2]; + BLI_str_escape(actname_esc, actname, sizeof(actname_esc)); + BLI_snprintf(buf, sizeof(buf), "pose.bones[\"%s\"]", actname_esc); } } else if (constname && constname[0]) { /* Constraint in Object */ - BLI_snprintf(buf, sizeof(buf), "constraints[\"%s\"]", constname); + char constname_esc[sizeof(((bConstraint *)NULL)->name) * 2]; + BLI_str_escape(constname_esc, constname, sizeof(constname_esc)); + BLI_snprintf(buf, sizeof(buf), "constraints[\"%s\"]", constname_esc); } else if (seq) { /* Sequence names in Scene */ - BLI_snprintf(buf, sizeof(buf), "sequence_editor.sequences_all[\"%s\"]", seq->name + 2); + char seq_name_esc[(sizeof(seq->name) - 2) * 2]; + BLI_str_escape(seq_name_esc, seq->name + 2, sizeof(seq_name_esc)); + BLI_snprintf(buf, sizeof(buf), "sequence_editor.sequences_all[\"%s\"]", seq_name_esc); } else { buf[0] = '\0'; /* empty string */ @@ -1999,12 +2012,12 @@ static void nlastrips_to_animdata(ID *id, ListBase *strips) } /* try to add this strip to the current NLA-Track (i.e. the 'last' one on the stack atm) */ - if (BKE_nlatrack_add_strip(nlt, strip) == 0) { + if (BKE_nlatrack_add_strip(nlt, strip, false) == 0) { /* trying to add to the current failed (no space), * so add a new track to the stack, and add to that... */ - nlt = BKE_nlatrack_add(adt, NULL); - BKE_nlatrack_add_strip(nlt, strip); + nlt = BKE_nlatrack_add(adt, NULL, false); + BKE_nlatrack_add_strip(nlt, strip, false); } /* ensure that strip has a name */ diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index 7468112b40e..433d64a5927 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -108,7 +108,8 @@ static void shapekey_foreach_id(ID *id, LibraryForeachIDData *data) static void shapekey_blend_write(BlendWriter *writer, ID *id, const void *id_address) { Key *key = (Key *)id; - if (key->id.us > 0 || BLO_write_is_undo(writer)) { + const bool is_undo = BLO_write_is_undo(writer); + if (key->id.us > 0 || is_undo) { /* write LibData */ BLO_write_id_struct(writer, Key, id_address, &key->id); BKE_id_blend_write(writer, &key->id); @@ -119,9 +120,15 @@ static void shapekey_blend_write(BlendWriter *writer, ID *id, const void *id_add /* direct data */ LISTBASE_FOREACH (KeyBlock *, kb, &key->block) { - BLO_write_struct(writer, KeyBlock, kb); - if (kb->data) { - BLO_write_raw(writer, kb->totelem * key->elemsize, kb->data); + KeyBlock tmp_kb = *kb; + /* Do not store actual geometry data in case this is a library override ID. */ + if (ID_IS_OVERRIDE_LIBRARY(key) && !is_undo) { + tmp_kb.totelem = 0; + tmp_kb.data = NULL; + } + BLO_write_struct_at_address(writer, KeyBlock, kb, &tmp_kb); + if (tmp_kb.data != NULL) { + BLO_write_raw(writer, tmp_kb.totelem * key->elemsize, tmp_kb.data); } } } diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index 8a699e31f37..fbad0d920ed 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -2054,7 +2054,7 @@ static void bke_view_layer_verify_aov_cb(void *userdata, const char *name, int UNUSED(channels), const char *UNUSED(chanid), - int UNUSED(type)) + eNodeSocketDatatype UNUSED(type)) { GHash *name_count = userdata; void **value_p; diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c index 21a77e2b45a..be7ce34f7e6 100644 --- a/source/blender/blenkernel/intern/lib_id.c +++ b/source/blender/blenkernel/intern/lib_id.c @@ -37,6 +37,7 @@ /* all types are needed here, in order to do memory operations */ #include "DNA_ID.h" #include "DNA_anim_types.h" +#include "DNA_collection_types.h" #include "DNA_gpencil_types.h" #include "DNA_key_types.h" #include "DNA_node_types.h" @@ -55,6 +56,7 @@ #include "BKE_anim_data.h" #include "BKE_armature.h" +#include "BKE_asset.h" #include "BKE_bpath.h" #include "BKE_context.h" #include "BKE_global.h" @@ -2264,6 +2266,12 @@ bool BKE_id_is_in_global_main(ID *id) return (id == NULL || BLI_findindex(which_libbase(G_MAIN, GS(id->name)), id) != -1); } +bool BKE_id_can_be_asset(const ID *id) +{ + return !ID_IS_LINKED(id) && !ID_IS_OVERRIDE_LIBRARY(id) && + BKE_idtype_idcode_is_linkable(GS(id->name)); +} + /************************* Datablock order in UI **************************/ static int *id_order_get(ID *id) @@ -2361,6 +2369,10 @@ void BKE_id_reorder(const ListBase *lb, ID *id, ID *relative, bool after) void BKE_id_blend_write(BlendWriter *writer, ID *id) { + if (id->asset_data) { + BKE_asset_metadata_write(writer, id->asset_data); + } + /* ID_WM's id->properties are considered runtime only, and never written in .blend file. */ if (id->properties && !ELEM(GS(id->name), ID_WM)) { IDP_BlendWrite(writer, id->properties); diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c index 1e45a3c1163..7199bd0f13c 100644 --- a/source/blender/blenkernel/intern/lib_id_delete.c +++ b/source/blender/blenkernel/intern/lib_id_delete.c @@ -31,6 +31,7 @@ #include "BLI_listbase.h" #include "BKE_anim_data.h" +#include "BKE_asset.h" #include "BKE_idprop.h" #include "BKE_idtype.h" #include "BKE_key.h" @@ -64,6 +65,10 @@ void BKE_libblock_free_data(ID *id, const bool do_id_user) id->override_library = NULL; } + if (id->asset_data) { + BKE_asset_metadata_free(&id->asset_data); + } + BKE_animdata_free(id, do_id_user); } diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c index d82315a0e7f..cabc80d4024 100644 --- a/source/blender/blenkernel/intern/lib_override.c +++ b/source/blender/blenkernel/intern/lib_override.c @@ -369,6 +369,7 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain) static bool lib_override_hierarchy_recursive_tag(Main *bmain, ID *id, const uint tag, + const uint missing_tag, Library *override_group_lib_reference) { void **entry_vp = BLI_ghash_lookup_p(bmain->relations->id_user_to_used, id); @@ -377,9 +378,16 @@ static bool lib_override_hierarchy_recursive_tag(Main *bmain, return (id->tag & tag) != 0; } + /* Note: in case some reference ID is missing from linked data (and therefore its override uses + * a placeholder as reference), use `missing_tag` instead of `tag` for this override. */ if (override_group_lib_reference != NULL && ID_IS_OVERRIDE_LIBRARY_REAL(id) && id->override_library->reference->lib == override_group_lib_reference) { - id->tag |= tag; + if (id->override_library->reference->tag & LIB_TAG_MISSING) { + id->tag |= missing_tag; + } + else { + id->tag |= tag; + } } /* This way we won't process again that ID, should we encounter it again through another @@ -397,7 +405,7 @@ static bool lib_override_hierarchy_recursive_tag(Main *bmain, /* We only consider IDs from the same library. */ if (entry->id_pointer != NULL && (*entry->id_pointer)->lib == id->lib) { if (lib_override_hierarchy_recursive_tag( - bmain, *entry->id_pointer, tag, override_group_lib_reference) && + bmain, *entry->id_pointer, tag, missing_tag, override_group_lib_reference) && override_group_lib_reference == NULL) { id->tag |= tag; } @@ -430,7 +438,7 @@ void BKE_lib_override_library_dependencies_tag(Main *bmain, /* We tag all intermediary data-blocks in-between two overridden ones (e.g. if a shape-key * has a driver using an armature object's bone, we need to override the shape-key/obdata, * the objects using them, etc.) */ - lib_override_hierarchy_recursive_tag(bmain, id_root, tag, NULL); + lib_override_hierarchy_recursive_tag(bmain, id_root, tag, 0, NULL); BKE_main_relations_free(bmain); } @@ -447,6 +455,7 @@ void BKE_lib_override_library_dependencies_tag(Main *bmain, void BKE_lib_override_library_override_group_tag(Main *bmain, ID *id_root, const uint tag, + const uint missing_tag, const bool do_create_main_relashionships) { if (do_create_main_relashionships) { @@ -456,7 +465,7 @@ void BKE_lib_override_library_override_group_tag(Main *bmain, /* We tag all liboverride data-blocks from the same library as reference one, * being used by the root ID. */ lib_override_hierarchy_recursive_tag( - bmain, id_root, tag, id_root->override_library->reference->lib); + bmain, id_root, tag, missing_tag, id_root->override_library->reference->lib); BKE_main_relations_free(bmain); } @@ -492,8 +501,9 @@ static int lib_override_library_make_tag_ids_cb(LibraryIDLinkCallbackData *cb_da } /* We tag all collections and objects for override. And we also tag all other data-blocks which - * would use one of those. */ - if (ELEM(GS(id->name), ID_OB, ID_GR)) { + * would use one of those. + * Note: missing IDs (aka placeholders) are never overridden. */ + if (ELEM(GS(id->name), ID_OB, ID_GR) && !(id->tag & LIB_TAG_MISSING)) { id->tag |= LIB_TAG_DOIT; } @@ -692,6 +702,12 @@ bool BKE_lib_override_library_proxy_convert(Main *bmain, &ob_proxy->proxy->id; ID *id_reference = is_override_instancing_object ? &ob_proxy_group->id : &ob_proxy->id; + /* In some cases the instance collection of a proxy object may be local (see e.g. T83875). Not + * sure this is a valid state, but for now just abort the overriding process. */ + if (!ID_IS_OVERRIDABLE_LIBRARY(id_root)) { + return false; + } + /* We manually convert the proxy object into a library override, further override handling will * then be handled by `BKE_lib_override_library_create()` just as for a regular override * creation. @@ -725,7 +741,7 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_ /* Make a mapping 'linked reference IDs' -> 'Local override IDs' of existing overrides, and tag * linked reference ones to be overridden again. */ - BKE_lib_override_library_override_group_tag(bmain, id_root, LIB_TAG_DOIT, true); + BKE_lib_override_library_override_group_tag(bmain, id_root, LIB_TAG_DOIT, LIB_TAG_MISSING, true); GHash *linkedref_to_old_override = BLI_ghash_new( BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__); @@ -835,6 +851,12 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_ } id->tag &= ~LIB_TAG_DOIT; } + /* Also cleanup old overrides that went missing in new linked data. */ + else if (id->tag & LIB_TAG_MISSING && !ID_IS_LINKED(id)) { + BLI_assert(ID_IS_OVERRIDE_LIBRARY(id)); + id->tag |= LIB_TAG_DOIT; + id->tag &= ~LIB_TAG_MISSING; + } } FOREACH_MAIN_ID_END; BKE_id_multi_tagged_delete(bmain); @@ -876,7 +898,7 @@ void BKE_lib_override_library_delete(Main *bmain, ID *id_root) id_root->tag |= LIB_TAG_DOIT; /* Tag all library overrides in the chains of dependencies from the given root one. */ - BKE_lib_override_library_override_group_tag(bmain, id_root, LIB_TAG_DOIT, true); + BKE_lib_override_library_override_group_tag(bmain, id_root, LIB_TAG_DOIT, LIB_TAG_DOIT, true); ID *id; FOREACH_MAIN_ID_BEGIN (bmain, id) { diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c index 9e3189afee9..56f7bb0be6f 100644 --- a/source/blender/blenkernel/intern/lib_remap.c +++ b/source/blender/blenkernel/intern/lib_remap.c @@ -24,6 +24,7 @@ #include "BLI_utildefines.h" +#include "DNA_collection_types.h" #include "DNA_object_types.h" #include "BKE_armature.h" @@ -342,7 +343,7 @@ static void libblock_remap_data_postprocess_obdata_relink(Main *bmain, Object *o static void libblock_remap_data_postprocess_nodetree_update(Main *bmain, ID *new_id) { /* Update all group nodes using a node group. */ - ntreeUpdateAllUsers(bmain, (bNodeTree *)new_id); + ntreeUpdateAllUsers(bmain, new_id); } /** diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c index 69e6535a59f..8542959d4b0 100644 --- a/source/blender/blenkernel/intern/linestyle.c +++ b/source/blender/blenkernel/intern/linestyle.c @@ -2017,7 +2017,7 @@ char *BKE_linestyle_path_to_color_ramp(FreestyleLineStyle *linestyle, ColorBand if (found) { char name_esc[sizeof(m->name) * 2]; - BLI_strescape(name_esc, m->name, sizeof(name_esc)); + BLI_str_escape(name_esc, m->name, sizeof(name_esc)); return BLI_sprintfN("color_modifiers[\"%s\"].color_ramp", name_esc); } } diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 9939656b720..00da1ad7770 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -173,24 +173,53 @@ static void mesh_foreach_id(ID *id, LibraryForeachIDData *data) static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address) { Mesh *mesh = (Mesh *)id; - if (mesh->id.us > 0 || BLO_write_is_undo(writer)) { - /* cache only - don't write */ - mesh->mface = NULL; - mesh->totface = 0; - memset(&mesh->fdata, 0, sizeof(mesh->fdata)); - memset(&mesh->runtime, 0, sizeof(mesh->runtime)); - + const bool is_undo = BLO_write_is_undo(writer); + if (mesh->id.us > 0 || is_undo) { CustomDataLayer *vlayers = NULL, vlayers_buff[CD_TEMP_CHUNK_SIZE]; CustomDataLayer *elayers = NULL, elayers_buff[CD_TEMP_CHUNK_SIZE]; CustomDataLayer *flayers = NULL, flayers_buff[CD_TEMP_CHUNK_SIZE]; CustomDataLayer *llayers = NULL, llayers_buff[CD_TEMP_CHUNK_SIZE]; CustomDataLayer *players = NULL, players_buff[CD_TEMP_CHUNK_SIZE]; - CustomData_blend_write_prepare(&mesh->vdata, &vlayers, vlayers_buff, ARRAY_SIZE(vlayers_buff)); - CustomData_blend_write_prepare(&mesh->edata, &elayers, elayers_buff, ARRAY_SIZE(elayers_buff)); + /* cache only - don't write */ + mesh->mface = NULL; + mesh->totface = 0; + memset(&mesh->fdata, 0, sizeof(mesh->fdata)); + memset(&mesh->runtime, 0, sizeof(mesh->runtime)); flayers = flayers_buff; - CustomData_blend_write_prepare(&mesh->ldata, &llayers, llayers_buff, ARRAY_SIZE(llayers_buff)); - CustomData_blend_write_prepare(&mesh->pdata, &players, players_buff, ARRAY_SIZE(players_buff)); + + /* Do not store actual geometry data in case this is a library override ID. */ + if (ID_IS_OVERRIDE_LIBRARY(mesh) && !is_undo) { + mesh->mvert = NULL; + mesh->totvert = 0; + memset(&mesh->vdata, 0, sizeof(mesh->vdata)); + vlayers = vlayers_buff; + + mesh->medge = NULL; + mesh->totedge = 0; + memset(&mesh->edata, 0, sizeof(mesh->edata)); + elayers = elayers_buff; + + mesh->mloop = NULL; + mesh->totloop = 0; + memset(&mesh->ldata, 0, sizeof(mesh->ldata)); + llayers = llayers_buff; + + mesh->mpoly = NULL; + mesh->totpoly = 0; + memset(&mesh->pdata, 0, sizeof(mesh->pdata)); + players = players_buff; + } + else { + CustomData_blend_write_prepare( + &mesh->vdata, &vlayers, vlayers_buff, ARRAY_SIZE(vlayers_buff)); + CustomData_blend_write_prepare( + &mesh->edata, &elayers, elayers_buff, ARRAY_SIZE(elayers_buff)); + CustomData_blend_write_prepare( + &mesh->ldata, &llayers, llayers_buff, ARRAY_SIZE(llayers_buff)); + CustomData_blend_write_prepare( + &mesh->pdata, &players, players_buff, ARRAY_SIZE(players_buff)); + } BLO_write_id_struct(writer, Mesh, id_address, &mesh->id); BKE_id_blend_write(writer, &mesh->id); diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c index 8272bd07411..73883afe19e 100644 --- a/source/blender/blenkernel/intern/mesh_convert.c +++ b/source/blender/blenkernel/intern/mesh_convert.c @@ -1460,7 +1460,7 @@ Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph, return result; } -/* This is a Mesh-based copy of the same function in DerivedMesh.c */ +/* 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) { KeyBlock *kb; diff --git a/source/blender/blenkernel/intern/mesh_fair.cc b/source/blender/blenkernel/intern/mesh_fair.cc new file mode 100644 index 00000000000..ccd1434b60b --- /dev/null +++ b/source/blender/blenkernel/intern/mesh_fair.cc @@ -0,0 +1,505 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Mesh Fairing algorithm designed by Brett Fedack, used in the addon "Mesh Fairing": + * https://github.com/fedackb/mesh-fairing. + */ + +/** \file + * \ingroup bke + */ + +#include "BLI_map.hh" +#include "BLI_math.h" +#include "BLI_vector.hh" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" + +#include "BKE_lib_id.h" +#include "BKE_lib_query.h" +#include "BKE_mesh.h" +#include "BKE_mesh_fair.h" +#include "BKE_mesh_mapping.h" + +#include "bmesh.h" +#include "bmesh_tools.h" + +#include "MEM_guardedalloc.h" +#include "eigen_capi.h" + +using blender::Map; +using blender::Vector; +using std::array; + +class VertexWeight { + public: + virtual float weight_at_index(const int index) = 0; + virtual ~VertexWeight() = default; +}; + +class LoopWeight { + public: + virtual float weight_at_index(const int index) = 0; + virtual ~LoopWeight() = default; +}; + +class FairingContext { + public: + /* Get coordinates of vertices which are adjacent to the loop with specified index. */ + virtual void adjacents_coords_from_loop(const int loop, + float r_adj_next[3], + float r_adj_prev[3]) = 0; + + /* Get the other vertex index for a loop. */ + virtual int other_vertex_index_from_loop(const int loop, const unsigned int v) = 0; + + int vertex_count_get() + { + return totvert_; + } + + int loop_count_get() + { + return totvert_; + } + + MeshElemMap *vertex_loop_map_get(const int v) + { + return &vlmap_[v]; + } + + float *vertex_deformation_co_get(const int v) + { + return co_[v]; + } + + virtual ~FairingContext() = default; + + void fair_vertices(bool *affected, + const eMeshFairingDepth depth, + VertexWeight *vertex_weight, + LoopWeight *loop_weight) + { + + fair_vertices_ex(affected, (int)depth, vertex_weight, loop_weight); + } + + protected: + Vector<float *> co_; + + int totvert_; + int totloop_; + + MeshElemMap *vlmap_; + int *vlmap_mem_; + + private: + void fair_setup_fairing(const int v, + const int i, + LinearSolver *solver, + float multiplier, + const int depth, + Map<int, int> &vert_col_map, + VertexWeight *vertex_weight, + LoopWeight *loop_weight) + { + if (depth == 0) { + if (vert_col_map.contains(v)) { + const int j = vert_col_map.lookup(v); + EIG_linear_solver_matrix_add(solver, i, j, -multiplier); + return; + } + for (int j = 0; j < 3; j++) { + EIG_linear_solver_right_hand_side_add(solver, j, i, multiplier * co_[v][j]); + } + return; + } + + float w_ij_sum = 0; + const float w_i = vertex_weight->weight_at_index(v); + MeshElemMap *vlmap_elem = &vlmap_[v]; + for (int l = 0; l < vlmap_elem->count; l++) { + const int l_index = vlmap_elem->indices[l]; + const int other_vert = other_vertex_index_from_loop(l_index, v); + const float w_ij = loop_weight->weight_at_index(l_index); + w_ij_sum += w_ij; + fair_setup_fairing(other_vert, + i, + solver, + w_i * w_ij * multiplier, + depth - 1, + vert_col_map, + vertex_weight, + loop_weight); + } + fair_setup_fairing(v, + i, + solver, + -1 * w_i * w_ij_sum * multiplier, + depth - 1, + vert_col_map, + vertex_weight, + loop_weight); + } + + void fair_vertices_ex(const bool *affected, + const int order, + VertexWeight *vertex_weight, + LoopWeight *loop_weight) + { + Map<int, int> vert_col_map; + int num_affected_vertices = 0; + for (int i = 0; i < totvert_; i++) { + if (!affected[i]) { + continue; + } + vert_col_map.add(i, num_affected_vertices); + num_affected_vertices++; + } + + /* Early return, nothing to do. */ + if (num_affected_vertices == 0 || num_affected_vertices == totvert_) { + return; + } + + /* Setup fairing matrices */ + LinearSolver *solver = EIG_linear_solver_new(num_affected_vertices, num_affected_vertices, 3); + for (auto item : vert_col_map.items()) { + const int v = item.key; + const int col = item.value; + fair_setup_fairing(v, col, solver, 1.0f, order, vert_col_map, vertex_weight, loop_weight); + } + + /* Solve linear system */ + EIG_linear_solver_solve(solver); + + /* Copy the result back to the mesh */ + for (auto item : vert_col_map.items()) { + const int v = item.key; + const int col = item.value; + for (int j = 0; j < 3; j++) { + co_[v][j] = EIG_linear_solver_variable_get(solver, j, col); + } + } + + /* Free solver data */ + EIG_linear_solver_delete(solver); + } +}; + +class MeshFairingContext : public FairingContext { + public: + MeshFairingContext(Mesh *mesh, MVert *deform_mverts) + { + totvert_ = mesh->totvert; + totloop_ = mesh->totloop; + + medge_ = mesh->medge; + mpoly_ = mesh->mpoly; + mloop_ = mesh->mloop; + BKE_mesh_vert_loop_map_create(&vlmap_, + &vlmap_mem_, + mesh->mpoly, + mesh->mloop, + mesh->totvert, + mesh->totpoly, + mesh->totloop); + + /* Deformation coords. */ + co_.reserve(mesh->totvert); + if (deform_mverts) { + for (int i = 0; i < mesh->totvert; i++) { + co_[i] = deform_mverts[i].co; + } + } + else { + for (int i = 0; i < mesh->totvert; i++) { + co_[i] = mesh->mvert[i].co; + } + } + + loop_to_poly_map_.reserve(mesh->totloop); + for (int i = 0; i < mesh->totpoly; i++) { + for (int l = 0; l < mesh->mpoly[i].totloop; l++) { + loop_to_poly_map_[l + mesh->mpoly[i].loopstart] = i; + } + } + } + + ~MeshFairingContext() override + { + MEM_SAFE_FREE(vlmap_); + MEM_SAFE_FREE(vlmap_mem_); + } + + void adjacents_coords_from_loop(const int loop, + float r_adj_next[3], + float r_adj_prev[3]) override + { + const int vert = mloop_[loop].v; + const MPoly *p = &mpoly_[loop_to_poly_map_[loop]]; + const int corner = poly_find_loop_from_vert(p, &mloop_[p->loopstart], vert); + copy_v3_v3(r_adj_next, co_[ME_POLY_LOOP_NEXT(mloop_, p, corner)->v]); + copy_v3_v3(r_adj_prev, co_[ME_POLY_LOOP_PREV(mloop_, p, corner)->v]); + } + + int other_vertex_index_from_loop(const int loop, const unsigned int v) override + { + MEdge *e = &medge_[mloop_[loop].e]; + if (e->v1 == v) { + return e->v2; + } + return e->v1; + } + + protected: + Mesh *mesh_; + MLoop *mloop_; + MPoly *mpoly_; + MEdge *medge_; + Vector<int> loop_to_poly_map_; +}; + +class BMeshFairingContext : public FairingContext { + public: + BMeshFairingContext(BMesh *bm) + { + this->bm = bm; + totvert_ = bm->totvert; + totloop_ = bm->totloop; + + BM_mesh_elem_table_ensure(bm, BM_VERT); + BM_mesh_elem_index_ensure(bm, BM_LOOP); + + /* Deformation coords. */ + co_.reserve(bm->totvert); + for (int i = 0; i < bm->totvert; i++) { + BMVert *v = BM_vert_at_index(bm, i); + co_[i] = v->co; + } + + bmloop_.reserve(bm->totloop); + vlmap_ = (MeshElemMap *)MEM_calloc_arrayN(sizeof(MeshElemMap), bm->totvert, "bmesh loop map"); + vlmap_mem_ = (int *)MEM_malloc_arrayN(sizeof(int), bm->totloop, "bmesh loop map mempool"); + + BMVert *v; + BMLoop *l; + BMIter iter; + BMIter loop_iter; + int index_iter = 0; + + /* This initializes both the bmloop and the vlmap for bmesh in a single loop. */ + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + int loop_count = 0; + const int vert_index = BM_elem_index_get(v); + vlmap_[vert_index].indices = &vlmap_mem_[index_iter]; + BM_ITER_ELEM (l, &loop_iter, v, BM_LOOPS_OF_VERT) { + const int loop_index = BM_elem_index_get(l); + bmloop_[loop_index] = l; + vlmap_mem_[index_iter] = loop_index; + index_iter++; + loop_count++; + } + vlmap_[vert_index].count = loop_count; + } + } + + ~BMeshFairingContext() override + { + MEM_SAFE_FREE(vlmap_); + MEM_SAFE_FREE(vlmap_mem_); + } + + void adjacents_coords_from_loop(const int loop, + float r_adj_next[3], + float r_adj_prev[3]) override + { + copy_v3_v3(r_adj_next, bmloop_[loop]->next->v->co); + copy_v3_v3(r_adj_prev, bmloop_[loop]->prev->v->co); + } + + int other_vertex_index_from_loop(const int loop, const unsigned int v) override + { + BMLoop *l = bmloop_[loop]; + BMVert *bmvert = BM_vert_at_index(bm, v); + BMVert *bm_other_vert = BM_edge_other_vert(l->e, bmvert); + return BM_elem_index_get(bm_other_vert); + } + + protected: + BMesh *bm; + Vector<BMLoop *> bmloop_; +}; + +class UniformVertexWeight : public VertexWeight { + public: + UniformVertexWeight(FairingContext *fairing_context) + { + const int totvert = fairing_context->vertex_count_get(); + vertex_weights_.reserve(totvert); + for (int i = 0; i < totvert; i++) { + const int tot_loop = fairing_context->vertex_loop_map_get(i)->count; + if (tot_loop != 0) { + vertex_weights_[i] = 1.0f / tot_loop; + } + else { + vertex_weights_[i] = FLT_MAX; + } + } + } + ~UniformVertexWeight() = default; + + float weight_at_index(const int index) override + { + return vertex_weights_[index]; + } + + private: + Vector<float> vertex_weights_; +}; + +class VoronoiVertexWeight : public VertexWeight { + + public: + VoronoiVertexWeight(FairingContext *fairing_context) + { + + const int totvert = fairing_context->vertex_count_get(); + vertex_weights_.reserve(totvert); + for (int i = 0; i < totvert; i++) { + + float area = 0.0f; + float a[3]; + copy_v3_v3(a, fairing_context->vertex_deformation_co_get(i)); + const float acute_threshold = M_PI_2; + + MeshElemMap *vlmap_elem = fairing_context->vertex_loop_map_get(i); + for (int l = 0; l < vlmap_elem->count; l++) { + const int l_index = vlmap_elem->indices[l]; + + float b[3], c[3], d[3]; + fairing_context->adjacents_coords_from_loop(l_index, b, c); + + if (angle_v3v3v3(c, fairing_context->vertex_deformation_co_get(i), b) < acute_threshold) { + calc_circumcenter(d, a, b, c); + } + else { + add_v3_v3v3(d, b, c); + mul_v3_fl(d, 0.5f); + } + + float t[3]; + add_v3_v3v3(t, a, b); + mul_v3_fl(t, 0.5f); + area += area_tri_v3(a, t, d); + + add_v3_v3v3(t, a, c); + mul_v3_fl(t, 0.5f); + area += area_tri_v3(a, d, t); + } + + vertex_weights_[i] = area != 0.0f ? 1.0f / area : 1e12; + } + } + ~VoronoiVertexWeight() = default; + + float weight_at_index(const int index) override + { + return vertex_weights_[index]; + } + + private: + Vector<float> vertex_weights_; + + void calc_circumcenter(float r[3], const float a[3], const float b[3], const float c[3]) + { + float ab[3]; + sub_v3_v3v3(ab, b, a); + + float ac[3]; + sub_v3_v3v3(ac, c, a); + + float ab_cross_ac[3]; + cross_v3_v3v3(ab_cross_ac, ab, ac); + + if (len_squared_v3(ab_cross_ac) > 0.0f) { + float d[3]; + cross_v3_v3v3(d, ab_cross_ac, ab); + mul_v3_fl(d, len_squared_v3(ac)); + + float t[3]; + cross_v3_v3v3(t, ac, ab_cross_ac); + mul_v3_fl(t, len_squared_v3(ab)); + + add_v3_v3(d, t); + + mul_v3_fl(d, 1.0f / (2.0f * len_squared_v3(ab_cross_ac))); + + add_v3_v3v3(r, a, d); + return; + } + copy_v3_v3(r, a); + } +}; + +class UniformLoopWeight : public LoopWeight { + public: + float weight_at_index(const int UNUSED(index)) override + { + return 1.0f; + } +}; + +static void prefair_and_fair_vertices(FairingContext *fairing_context, + bool *affected_vertices, + const eMeshFairingDepth depth) +{ + /* Prefair. */ + UniformVertexWeight *uniform_vertex_weights = new UniformVertexWeight(fairing_context); + UniformLoopWeight *uniform_loop_weights = new UniformLoopWeight(); + fairing_context->fair_vertices( + affected_vertices, depth, uniform_vertex_weights, uniform_loop_weights); + delete uniform_vertex_weights; + + /* Fair. */ + VoronoiVertexWeight *voronoi_vertex_weights = new VoronoiVertexWeight(fairing_context); + /* TODO: Implemente cotangent loop weights. */ + fairing_context->fair_vertices( + affected_vertices, depth, voronoi_vertex_weights, uniform_loop_weights); + + delete uniform_loop_weights; + delete voronoi_vertex_weights; +} + +void BKE_mesh_prefair_and_fair_vertices(struct Mesh *mesh, + struct MVert *deform_mverts, + bool *affect_vertices, + const eMeshFairingDepth depth) +{ + MeshFairingContext *fairing_context = new MeshFairingContext(mesh, deform_mverts); + prefair_and_fair_vertices(fairing_context, affect_vertices, depth); + delete fairing_context; +} + +void BKE_bmesh_prefair_and_fair_vertices(struct BMesh *bm, + bool *affect_vertices, + const eMeshFairingDepth depth) +{ + BMeshFairingContext *fairing_context = new BMeshFairingContext(bm); + prefair_and_fair_vertices(fairing_context, affect_vertices, depth); + delete fairing_context; +} diff --git a/source/blender/blenkernel/intern/mesh_validate.cc b/source/blender/blenkernel/intern/mesh_validate.cc index 16733729be0..0aaca33124a 100644 --- a/source/blender/blenkernel/intern/mesh_validate.cc +++ b/source/blender/blenkernel/intern/mesh_validate.cc @@ -76,10 +76,10 @@ struct OrderedEdge { }; /* The map first contains an edge pointer and later an index. */ -typedef union OrigEdgeOrIndex { +union OrigEdgeOrIndex { const MEdge *original_edge; int index; -} OrigEdgeOrIndex; +}; using EdgeMap = Map<OrderedEdge, OrigEdgeOrIndex>; static void reserve_hash_maps(const Mesh *mesh, diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 7865d44c446..ba0f59f6363 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -38,6 +38,7 @@ #include "DNA_armature_types.h" #include "DNA_cloth_types.h" +#include "DNA_dynamicpaint_types.h" #include "DNA_fluid_types.h" #include "DNA_gpencil_modifier_types.h" #include "DNA_mesh_types.h" @@ -575,16 +576,15 @@ bool BKE_modifier_is_enabled(const struct Scene *scene, ModifierData *md, int re } /** - * Check whether given modifier is local when the object is a library override. + * Check whether given modifier is not local (i.e. from linked data) when the object is a library + * override. * - * \param md May be NULL, in which case we consider it as a non-local modifier case. - * - * \note This check is only valid for a liboverride data-block, it always return \a true otherwise. + * \param md: May be NULL, in which case we consider it as a non-local modifier case. */ -bool BKE_modifier_is_local_in_liboverride(const Object *ob, const ModifierData *md) +bool BKE_modifier_is_nonlocal_in_liboverride(const Object *ob, const ModifierData *md) { - return (!ID_IS_OVERRIDE_LIBRARY(ob) || - (md != NULL && (md->flag & eModifierFlag_OverrideLibrary_Local) != 0)); + return (ID_IS_OVERRIDE_LIBRARY(ob) && + (md == NULL || (md->flag & eModifierFlag_OverrideLibrary_Local) == 0)); } CDMaskLink *BKE_modifier_calc_data_masks(struct Scene *scene, diff --git a/source/blender/blenkernel/intern/multires_unsubdivide.h b/source/blender/blenkernel/intern/multires_unsubdivide.h index 39c6da0b6c8..0a03387282f 100644 --- a/source/blender/blenkernel/intern/multires_unsubdivide.h +++ b/source/blender/blenkernel/intern/multires_unsubdivide.h @@ -26,10 +26,8 @@ #include "BLI_sys_types.h" struct BMesh; -struct Depsgraph; struct Mesh; struct MultiresModifierData; -struct Object; typedef struct MultiresUnsubdivideGrid { /* For sanity checks. */ diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index 56bd83140bf..75230f9045c 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -280,7 +280,7 @@ void BKE_nla_tracks_copy(Main *bmain, ListBase *dst, ListBase *src, const int fl /* Add a NLA Track to the given AnimData * - prev: NLA-Track to add the new one after */ -NlaTrack *BKE_nlatrack_add(AnimData *adt, NlaTrack *prev) +NlaTrack *BKE_nlatrack_add(AnimData *adt, NlaTrack *prev, const bool is_liboverride) { NlaTrack *nlt; @@ -293,11 +293,15 @@ NlaTrack *BKE_nlatrack_add(AnimData *adt, NlaTrack *prev) nlt = MEM_callocN(sizeof(NlaTrack), "NlaTrack"); /* set settings requiring the track to not be part of the stack yet */ - nlt->flag = NLATRACK_SELECTED; + nlt->flag = NLATRACK_SELECTED | NLATRACK_OVERRIDELIBRARY_LOCAL; nlt->index = BLI_listbase_count(&adt->nla_tracks); /* add track to stack, and make it the active one */ - if (prev) { + if (is_liboverride) { + for (; prev != NULL && (prev->flag & NLATRACK_OVERRIDELIBRARY_LOCAL) == 0; prev = prev->next) { + } + } + if (prev != NULL) { BLI_insertlinkafter(&adt->nla_tracks, prev, nlt); } else { @@ -330,11 +334,8 @@ NlaStrip *BKE_nlastrip_new(bAction *act) /* generic settings * - selected flag to highlight this to the user * - (XXX) disabled Auto-Blends, as this was often causing some unwanted effects - * - (XXX) synchronization of strip-length in accordance with changes to action-length - * is not done though, since this should only really happens in editmode for strips now - * though this decision is still subject to further review... */ - strip->flag = NLASTRIP_FLAG_SELECT; + strip->flag = NLASTRIP_FLAG_SELECT | NLASTRIP_FLAG_SYNC_LENGTH; /* assign the action reference */ strip->act = act; @@ -359,7 +360,7 @@ NlaStrip *BKE_nlastrip_new(bAction *act) /* Add new NLA-strip to the top of the NLA stack - i.e. * into the last track if space, or a new one otherwise. */ -NlaStrip *BKE_nlastack_add_strip(AnimData *adt, bAction *act) +NlaStrip *BKE_nlastack_add_strip(AnimData *adt, bAction *act, const bool is_liboverride) { NlaStrip *strip; NlaTrack *nlt; @@ -376,12 +377,12 @@ NlaStrip *BKE_nlastack_add_strip(AnimData *adt, bAction *act) } /* firstly try adding strip to last track, but if that fails, add to a new track */ - if (BKE_nlatrack_add_strip(adt->nla_tracks.last, strip) == 0) { + if (BKE_nlatrack_add_strip(adt->nla_tracks.last, strip, is_liboverride) == 0) { /* trying to add to the last track failed (no track or no space), * so add a new track to the stack, and add to that... */ - nlt = BKE_nlatrack_add(adt, NULL); - BKE_nlatrack_add_strip(nlt, strip); + nlt = BKE_nlatrack_add(adt, NULL, is_liboverride); + BKE_nlatrack_add_strip(nlt, strip, is_liboverride); } /* automatically name it too */ @@ -1138,15 +1139,16 @@ void BKE_nlatrack_sort_strips(NlaTrack *nlt) /* Add the given NLA-Strip to the given NLA-Track, assuming that it * isn't currently attached to another one */ -bool BKE_nlatrack_add_strip(NlaTrack *nlt, NlaStrip *strip) +bool BKE_nlatrack_add_strip(NlaTrack *nlt, NlaStrip *strip, const bool is_liboverride) { /* sanity checks */ if (ELEM(NULL, nlt, strip)) { return false; } - /* do not allow adding strips if this track is locked */ - if (nlt->flag & NLATRACK_PROTECTED) { + /* Do not allow adding strips if this track is locked, or not a local one in liboverride case. */ + if (nlt->flag & NLATRACK_PROTECTED || + (is_liboverride && (nlt->flag & NLATRACK_OVERRIDELIBRARY_LOCAL) == 0)) { return false; } @@ -1186,6 +1188,18 @@ bool BKE_nlatrack_get_bounds(NlaTrack *nlt, float bounds[2]) return true; } +/** + * Check whether given NLA track is not local (i.e. from linked data) when the object is a library + * override. + * + * \param nlt: May be NULL, in which case we consider it as a non-local track case. + */ +bool BKE_nlatrack_is_nonlocal_in_liboverride(const ID *id, const NlaTrack *nlt) +{ + return (ID_IS_OVERRIDE_LIBRARY(id) && + (nlt == NULL || (nlt->flag & NLATRACK_OVERRIDELIBRARY_LOCAL) == 0)); +} + /* NLA Strips -------------------------------------- */ /* Find the active NLA-strip within the given track */ @@ -1857,7 +1871,7 @@ bool BKE_nla_action_is_stashed(AnimData *adt, bAction *act) /* "Stash" an action (i.e. store it as a track/layer in the NLA, but non-contributing) * to retain it in the file for future uses */ -bool BKE_nla_action_stash(AnimData *adt) +bool BKE_nla_action_stash(AnimData *adt, const bool is_liboverride) { NlaTrack *prev_track = NULL; NlaTrack *nlt; @@ -1881,7 +1895,7 @@ bool BKE_nla_action_stash(AnimData *adt) } } - nlt = BKE_nlatrack_add(adt, prev_track); + nlt = BKE_nlatrack_add(adt, prev_track, is_liboverride); BLI_assert(nlt != NULL); /* We need to ensure that if there wasn't any previous instance, @@ -1901,7 +1915,7 @@ bool BKE_nla_action_stash(AnimData *adt) strip = BKE_nlastrip_new(adt->action); BLI_assert(strip != NULL); - BKE_nlatrack_add_strip(nlt, strip); + BKE_nlatrack_add_strip(nlt, strip, is_liboverride); BKE_nlastrip_validate_name(adt, strip); /* mark the stash track and strip so that they doesn't disturb the stack animation, @@ -1931,7 +1945,7 @@ bool BKE_nla_action_stash(AnimData *adt) * so no checks for this are performed. */ /* TODO: maybe we should have checks for this too... */ -void BKE_nla_action_pushdown(AnimData *adt) +void BKE_nla_action_pushdown(AnimData *adt, const bool is_liboverride) { NlaStrip *strip; const bool is_first = (adt) && (adt->nla_tracks.first == NULL); @@ -1952,7 +1966,7 @@ void BKE_nla_action_pushdown(AnimData *adt) } /* add a new NLA strip to the track, which references the active action */ - strip = BKE_nlastack_add_strip(adt, adt->action); + strip = BKE_nlastack_add_strip(adt, adt->action, is_liboverride); if (strip == NULL) { return; } @@ -2273,6 +2287,11 @@ void BKE_nla_blend_read_lib(BlendLibReader *reader, ID *id, ListBase *tracks) { /* we only care about the NLA strips inside the tracks */ LISTBASE_FOREACH (NlaTrack *, nlt, tracks) { + /* If linking from a library, clear 'local' library override flag. */ + if (id->lib != NULL) { + nlt->flag &= ~NLATRACK_OVERRIDELIBRARY_LOCAL; + } + blend_lib_read_nla_strips(reader, id, &nlt->strips); } } diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index b564a4c468b..676d0bf9385 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -35,6 +35,7 @@ #include "DNA_action_types.h" #include "DNA_anim_types.h" +#include "DNA_collection_types.h" #include "DNA_gpencil_types.h" #include "DNA_light_types.h" #include "DNA_linestyle_types.h" @@ -59,6 +60,7 @@ #include "BKE_anim_data.h" #include "BKE_animsys.h" #include "BKE_colortools.h" +#include "BKE_cryptomatte.h" #include "BKE_global.h" #include "BKE_idprop.h" #include "BKE_idtype.h" @@ -274,6 +276,11 @@ static void library_foreach_node_socket(LibraryForeachIDData *data, bNodeSocket BKE_LIB_FOREACHID_PROCESS(data, default_value->value, IDWALK_CB_USER); break; } + case SOCK_COLLECTION: { + bNodeSocketValueCollection *default_value = sock->default_value; + BKE_LIB_FOREACHID_PROCESS(data, default_value->value, IDWALK_CB_USER); + break; + } case SOCK_FLOAT: case SOCK_VECTOR: case SOCK_RGBA: @@ -373,6 +380,9 @@ static void write_node_socket_default_value(BlendWriter *writer, bNodeSocket *so case SOCK_IMAGE: BLO_write_struct(writer, bNodeSocketValueImage, sock->default_value); break; + case SOCK_COLLECTION: + BLO_write_struct(writer, bNodeSocketValueCollection, sock->default_value); + break; case __SOCK_MESH: case SOCK_CUSTOM: case SOCK_SHADER: @@ -482,10 +492,18 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree) } else if ((ntree->type == NTREE_COMPOSIT) && (node->type == CMP_NODE_CRYPTOMATTE)) { NodeCryptomatte *nc = (NodeCryptomatte *)node->storage; + /* Update the matte_id so the files can be opened in versions that don't + * use `CryptomatteEntry`. */ + MEM_SAFE_FREE(nc->matte_id); + nc->matte_id = BKE_cryptomatte_entries_to_matte_id(nc); if (nc->matte_id) { BLO_write_string(writer, nc->matte_id); } + LISTBASE_FOREACH (CryptomatteEntry *, entry, &nc->entries) { + BLO_write_struct(writer, CryptomatteEntry, entry); + } BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage); + MEM_SAFE_FREE(nc->matte_id); } else if (node->typeinfo != &NodeTypeUndefined) { BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage); @@ -637,6 +655,7 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree) case CMP_NODE_CRYPTOMATTE: { NodeCryptomatte *nc = (NodeCryptomatte *)node->storage; BLO_read_data_address(reader, &nc->matte_id); + BLO_read_list(reader, &nc->entries); break; } case TEX_NODE_IMAGE: { @@ -655,7 +674,6 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree) /* and we connect the rest */ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { BLO_read_data_address(reader, &node->parent); - node->lasty = 0; LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { direct_link_node_socket(reader, sock); @@ -709,6 +727,11 @@ static void lib_link_node_socket(BlendLibReader *reader, Library *lib, bNodeSock BLO_read_id_address(reader, lib, &default_value->value); break; } + case SOCK_COLLECTION: { + bNodeSocketValueImage *default_value = sock->default_value; + BLO_read_id_address(reader, lib, &default_value->value); + break; + } case SOCK_FLOAT: case SOCK_VECTOR: case SOCK_RGBA: @@ -788,6 +811,11 @@ static void expand_node_socket(BlendExpander *expander, bNodeSocket *sock) BLO_expand(expander, default_value->value); break; } + case SOCK_COLLECTION: { + bNodeSocketValueCollection *default_value = sock->default_value; + BLO_expand(expander, default_value->value); + break; + } case SOCK_FLOAT: case SOCK_VECTOR: case SOCK_RGBA: @@ -1345,6 +1373,11 @@ static void socket_id_user_increment(bNodeSocket *sock) id_us_plus((ID *)default_value->value); break; } + case SOCK_COLLECTION: { + bNodeSocketValueCollection *default_value = sock->default_value; + id_us_plus((ID *)default_value->value); + break; + } case SOCK_FLOAT: case SOCK_VECTOR: case SOCK_RGBA: @@ -1372,6 +1405,11 @@ static void socket_id_user_decrement(bNodeSocket *sock) id_us_min(&default_value->value->id); break; } + case SOCK_COLLECTION: { + bNodeSocketValueCollection *default_value = sock->default_value; + id_us_min(&default_value->value->id); + break; + } case SOCK_FLOAT: case SOCK_VECTOR: case SOCK_RGBA: @@ -1511,6 +1549,8 @@ const char *nodeStaticSocketType(int type, int subtype) return "NodeSocketImage"; case SOCK_GEOMETRY: return "NodeSocketGeometry"; + case SOCK_COLLECTION: + return "NodeSocketCollection"; } return NULL; } @@ -1578,6 +1618,8 @@ const char *nodeStaticSocketInterfaceType(int type, int subtype) return "NodeSocketInterfaceImage"; case SOCK_GEOMETRY: return "NodeSocketInterfaceGeometry"; + case SOCK_COLLECTION: + return "NodeSocketInterfaceCollection"; } return NULL; } @@ -2708,7 +2750,7 @@ void nodeRemoveNode(Main *bmain, bNodeTree *ntree, bNode *node, bool do_id_user) char propname_esc[MAX_IDPROP_NAME * 2]; char prefix[MAX_IDPROP_NAME * 2]; - BLI_strescape(propname_esc, node->name, sizeof(propname_esc)); + BLI_str_escape(propname_esc, node->name, sizeof(propname_esc)); BLI_snprintf(prefix, sizeof(prefix), "nodes[\"%s\"]", propname_esc); if (BKE_animdata_fix_paths_remove((ID *)ntree, prefix)) { @@ -3960,9 +4002,9 @@ void ntreeUpdateAllNew(Main *main) FOREACH_NODETREE_END; } -void ntreeUpdateAllUsers(Main *main, bNodeTree *ngroup) +void ntreeUpdateAllUsers(Main *main, ID *id) { - if (ngroup == NULL) { + if (id == NULL) { return; } @@ -3971,7 +4013,7 @@ void ntreeUpdateAllUsers(Main *main, bNodeTree *ngroup) bool need_update = false; LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { - if (node->id == &ngroup->id) { + if (node->id == id) { if (node->typeinfo->group_update_func) { node->typeinfo->group_update_func(ntree, node); } @@ -3986,13 +4028,16 @@ void ntreeUpdateAllUsers(Main *main, bNodeTree *ngroup) } FOREACH_NODETREE_END; - if (ngroup->type == NTREE_GEOMETRY) { - LISTBASE_FOREACH (Object *, object, &main->objects) { - LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) { - if (md->type == eModifierType_Nodes) { - NodesModifierData *nmd = (NodesModifierData *)md; - if (nmd->node_group == ngroup) { - MOD_nodes_update_interface(object, nmd); + if (GS(id->name) == ID_NT) { + bNodeTree *ngroup = (bNodeTree *)id; + if (ngroup->type == NTREE_GEOMETRY) { + LISTBASE_FOREACH (Object *, object, &main->objects) { + LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) { + if (md->type == eModifierType_Nodes) { + NodesModifierData *nmd = (NodesModifierData *)md; + if (nmd->node_group == ngroup) { + MOD_nodes_update_interface(object, nmd); + } } } } @@ -4041,7 +4086,7 @@ void ntreeUpdateTree(Main *bmain, bNodeTree *ntree) } if (bmain) { - ntreeUpdateAllUsers(bmain, ntree); + ntreeUpdateAllUsers(bmain, &ntree->id); } if (ntree->update & (NTREE_UPDATE_LINKS | NTREE_UPDATE_NODES)) { @@ -4451,6 +4496,7 @@ static void registerCompositNodes(void) register_node_type_cmp_hue_sat(); register_node_type_cmp_brightcontrast(); register_node_type_cmp_gamma(); + register_node_type_cmp_exposure(); register_node_type_cmp_invert(); register_node_type_cmp_alphaover(); register_node_type_cmp_zcombine(); @@ -4682,6 +4728,8 @@ static void registerGeometryNodes(void) { register_node_type_geo_group(); + register_node_type_geo_attribute_compare(); + register_node_type_geo_attribute_fill(); register_node_type_geo_triangulate(); register_node_type_geo_edge_split(); register_node_type_geo_transform(); @@ -4689,10 +4737,13 @@ static void registerGeometryNodes(void) register_node_type_geo_boolean(); register_node_type_geo_point_distribute(); register_node_type_geo_point_instance(); + register_node_type_geo_point_separate(); register_node_type_geo_object_info(); - register_node_type_geo_random_attribute(); + register_node_type_geo_attribute_randomize(); register_node_type_geo_attribute_math(); register_node_type_geo_join_geometry(); + register_node_type_geo_attribute_mix(); + register_node_type_geo_attribute_color_ramp(); } static void registerFunctionNodes(void) @@ -4704,6 +4755,7 @@ static void registerFunctionNodes(void) register_node_type_fn_combine_strings(); register_node_type_fn_object_transforms(); register_node_type_fn_random_float(); + register_node_type_fn_input_vector(); } void BKE_node_system_init(void) diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index d747da2213e..8764232e56b 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -38,6 +38,7 @@ #include "DNA_collection_types.h" #include "DNA_constraint_types.h" #include "DNA_defaults.h" +#include "DNA_dynamicpaint_types.h" #include "DNA_effect_types.h" #include "DNA_fluid_types.h" #include "DNA_gpencil_modifier_types.h" @@ -1325,7 +1326,7 @@ bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type) return (mti->modifyHair != NULL) || (mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly); } if (ob->type == OB_POINTCLOUD) { - return (mti->modifyPointCloud != NULL); + return (mti->modifyGeometrySet != NULL); } if (ob->type == OB_VOLUME) { return (mti->modifyVolume != NULL); @@ -2208,7 +2209,9 @@ ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys, const int f BLI_listbase_clear(&psysn->childcachebufs); if (flag & LIB_ID_CREATE_NO_MAIN) { - BLI_assert((psys->flag & PSYS_SHARED_CACHES) == 0); + /* XXX Disabled, fails when evaluating depsgraph after copying ID with no main for preview + * creation. */ + // BLI_assert((psys->flag & PSYS_SHARED_CACHES) == 0); psysn->flag |= PSYS_SHARED_CACHES; BLI_assert(psysn->pointcache != NULL); } @@ -5217,8 +5220,11 @@ bool BKE_object_modifier_use_time(Object *ob, ModifierData *md) AnimData *adt = ob->adt; FCurve *fcu; - char pattern[MAX_NAME + 16]; - BLI_snprintf(pattern, sizeof(pattern), "modifiers[\"%s\"]", md->name); + char md_name_esc[sizeof(md->name) * 2]; + BLI_str_escape(md_name_esc, md->name, sizeof(md_name_esc)); + + char pattern[sizeof(md_name_esc) + 16]; + BLI_snprintf(pattern, sizeof(pattern), "modifiers[\"%s\"]", md_name_esc); /* action - check for F-Curves with paths containing 'modifiers[' */ if (adt->action) { @@ -5260,8 +5266,11 @@ bool BKE_object_modifier_gpencil_use_time(Object *ob, GpencilModifierData *md) AnimData *adt = ob->adt; FCurve *fcu; - char pattern[MAX_NAME + 32]; - BLI_snprintf(pattern, sizeof(pattern), "grease_pencil_modifiers[\"%s\"]", md->name); + char md_name_esc[sizeof(md->name) * 2]; + BLI_str_escape(md_name_esc, md->name, sizeof(md_name_esc)); + + char pattern[sizeof(md_name_esc) + 32]; + BLI_snprintf(pattern, sizeof(pattern), "grease_pencil_modifiers[\"%s\"]", md_name_esc); /* action - check for F-Curves with paths containing 'grease_pencil_modifiers[' */ if (adt->action) { @@ -5295,8 +5304,11 @@ bool BKE_object_shaderfx_use_time(Object *ob, ShaderFxData *fx) AnimData *adt = ob->adt; FCurve *fcu; - char pattern[MAX_NAME + 32]; - BLI_snprintf(pattern, sizeof(pattern), "shader_effects[\"%s\"]", fx->name); + char fx_name_esc[sizeof(fx->name) * 2]; + BLI_str_escape(fx_name_esc, fx->name, sizeof(fx_name_esc)); + + char pattern[sizeof(fx_name_esc) + 32]; + BLI_snprintf(pattern, sizeof(pattern), "shader_effects[\"%s\"]", fx_name_esc); /* action - check for F-Curves with paths containing string[' */ if (adt->action) { diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c index 9a8c560f116..8fa708f31cb 100644 --- a/source/blender/blenkernel/intern/object_dupli.c +++ b/source/blender/blenkernel/intern/object_dupli.c @@ -816,26 +816,58 @@ static void make_duplis_instances_component(const DupliContext *ctx) float(*positions)[3]; float(*rotations)[3]; float(*scales)[3]; - Object **objects; + InstancedData *instanced_data; const int amount = BKE_geometry_set_instances( - ctx->object->runtime.geometry_set_eval, &positions, &rotations, &scales, &objects); + ctx->object->runtime.geometry_set_eval, &positions, &rotations, &scales, &instanced_data); for (int i = 0; i < amount; i++) { - Object *object = objects[i]; - if (object == NULL) { - continue; - } + InstancedData *data = &instanced_data[i]; + float scale_matrix[4][4]; size_to_mat4(scale_matrix, scales[i]); float rotation_matrix[4][4]; eul_to_mat4(rotation_matrix, rotations[i]); - float matrix[4][4]; - mul_m4_m4m4(matrix, rotation_matrix, scale_matrix); - copy_v3_v3(matrix[3], positions[i]); - mul_m4_m4_pre(matrix, ctx->object->obmat); + float instance_offset_matrix[4][4]; + mul_m4_m4m4(instance_offset_matrix, rotation_matrix, scale_matrix); + copy_v3_v3(instance_offset_matrix[3], positions[i]); + + if (data->type == INSTANCE_DATA_TYPE_OBJECT) { + Object *object = data->data.object; + if (object != NULL) { + float matrix[4][4]; + mul_m4_m4m4(matrix, ctx->object->obmat, instance_offset_matrix); + make_dupli(ctx, object, matrix, i); + + float space_matrix[4][4]; + mul_m4_m4m4(space_matrix, instance_offset_matrix, object->imat); + mul_m4_m4_pre(space_matrix, ctx->object->obmat); + make_recursive_duplis(ctx, object, space_matrix, i); + } + } + else if (data->type == INSTANCE_DATA_TYPE_COLLECTION) { + Collection *collection = data->data.collection; + if (collection != NULL) { + float collection_matrix[4][4]; + unit_m4(collection_matrix); + sub_v3_v3(collection_matrix[3], collection->instance_offset); + mul_m4_m4_pre(collection_matrix, instance_offset_matrix); + mul_m4_m4_pre(collection_matrix, ctx->object->obmat); + + eEvaluationMode mode = DEG_get_mode(ctx->depsgraph); + FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (collection, object, mode) { + if (object == ctx->object) { + continue; + } - make_dupli(ctx, object, matrix, i); - make_recursive_duplis(ctx, object, matrix, i); + float instance_matrix[4][4]; + mul_m4_m4m4(instance_matrix, collection_matrix, object->obmat); + + make_dupli(ctx, object, instance_matrix, i); + make_recursive_duplis(ctx, object, collection_matrix, i); + } + FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END; + } + } } } diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c index 915ee56e2f7..1b4dc98252a 100644 --- a/source/blender/blenkernel/intern/object_update.c +++ b/source/blender/blenkernel/intern/object_update.c @@ -28,6 +28,7 @@ #include "DNA_key_types.h" #include "DNA_material_types.h" #include "DNA_mesh_types.h" +#include "DNA_modifier_types.h" #include "DNA_scene_types.h" #include "BLI_blenlib.h" diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index d516de535f9..dce45f44583 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -41,6 +41,7 @@ #include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "DNA_object_force_types.h" #include "DNA_particle_types.h" #include "DNA_scene_types.h" diff --git a/source/blender/blenkernel/intern/particle_child.c b/source/blender/blenkernel/intern/particle_child.c index 98a55c3de95..6e0965650d3 100644 --- a/source/blender/blenkernel/intern/particle_child.c +++ b/source/blender/blenkernel/intern/particle_child.c @@ -25,6 +25,7 @@ #include "BLI_noise.h" #include "DNA_material_types.h" +#include "DNA_object_types.h" #include "BKE_colortools.h" #include "BKE_particle.h" diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c index 194593be4ff..c3cc9136057 100644 --- a/source/blender/blenkernel/intern/particle_distribute.c +++ b/source/blender/blenkernel/intern/particle_distribute.c @@ -40,6 +40,7 @@ #include "DNA_particle_types.h" #include "DNA_scene_types.h" +#include "BKE_customdata.h" #include "BKE_global.h" #include "BKE_lib_id.h" #include "BKE_mesh.h" diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 35265cf8b68..71df28c8b42 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -34,6 +34,7 @@ #include "DNA_anim_types.h" #include "DNA_boid_types.h" +#include "DNA_cloth_types.h" #include "DNA_curve_types.h" #include "DNA_listBase.h" #include "DNA_mesh_types.h" @@ -4978,6 +4979,24 @@ void particle_system_update(struct Depsgraph *depsgraph, /* ID looper */ +/* unfortunately PSys and modifier ID loopers are not directly compatible, so we need this struct + * and the callback below to map the former to the latter (thanks to psys embedding a Cloth + * modifier data struct now, for Hair physics simulations). */ +typedef struct ParticleSystemIDLoopForModifier { + ParticleSystem *psys; + ParticleSystemIDFunc func; + void *userdata; +} ParticleSystemIDLoopForModifier; + +static void particlesystem_modifiersForeachIDLink(void *user_data, + Object *UNUSED(object), + ID **id_pointer, + int cb_flag) +{ + ParticleSystemIDLoopForModifier *data = (ParticleSystemIDLoopForModifier *)user_data; + data->func(data->psys, id_pointer, data->userdata, cb_flag); +} + void BKE_particlesystem_id_loop(ParticleSystem *psys, ParticleSystemIDFunc func, void *userdata) { ParticleTarget *pt; @@ -4986,6 +5005,16 @@ void BKE_particlesystem_id_loop(ParticleSystem *psys, ParticleSystemIDFunc func, func(psys, (ID **)&psys->target_ob, userdata, IDWALK_CB_NOP); func(psys, (ID **)&psys->parent, userdata, IDWALK_CB_NOP); + if (psys->clmd != NULL) { + const ModifierTypeInfo *mti = BKE_modifier_get_info(psys->clmd->modifier.type); + + if (mti->foreachIDLink != NULL) { + ParticleSystemIDLoopForModifier data = {.psys = psys, .func = func, .userdata = userdata}; + mti->foreachIDLink( + &psys->clmd->modifier, NULL, particlesystem_modifiersForeachIDLink, &data); + } + } + for (pt = psys->targets.first; pt; pt = pt->next) { func(psys, (ID **)&pt->ob, userdata, IDWALK_CB_NOP); } diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc index 5f6685817b9..7bd14e80333 100644 --- a/source/blender/blenkernel/intern/pointcloud.cc +++ b/source/blender/blenkernel/intern/pointcloud.cc @@ -365,12 +365,31 @@ static void pointcloud_evaluate_modifiers(struct Depsgraph *depsgraph, continue; } - if (mti->modifyPointCloud) { - mti->modifyPointCloud(md, &mectx, &geometry_set); + if (mti->modifyGeometrySet) { + mti->modifyGeometrySet(md, &mectx, &geometry_set); } } } +static PointCloud *take_pointcloud_ownership_from_geometry_set(GeometrySet &geometry_set) +{ + if (!geometry_set.has<PointCloudComponent>()) { + return nullptr; + } + PointCloudComponent &pointcloud_component = + geometry_set.get_component_for_write<PointCloudComponent>(); + PointCloud *pointcloud = pointcloud_component.release(); + if (pointcloud != nullptr) { + /* Add back, but as read-only non-owning component. */ + pointcloud_component.replace(pointcloud, GeometryOwnershipType::ReadOnly); + } + else { + /* The component was empty, we can also remove it. */ + geometry_set.remove<PointCloudComponent>(); + } + return pointcloud; +} + void BKE_pointcloud_data_update(struct Depsgraph *depsgraph, struct Scene *scene, Object *object) { /* Free any evaluated data and restore original data. */ @@ -382,10 +401,17 @@ void BKE_pointcloud_data_update(struct Depsgraph *depsgraph, struct Scene *scene GeometryOwnershipType::ReadOnly); pointcloud_evaluate_modifiers(depsgraph, scene, object, geometry_set); + PointCloud *pointcloud_eval = take_pointcloud_ownership_from_geometry_set(geometry_set); + + /* If the geometry set did not contain a point cloud, we still create an empty one. */ + if (pointcloud_eval == nullptr) { + pointcloud_eval = BKE_pointcloud_new_nomain(0); + } + /* Assign evaluated object. */ - PointCloud *dummy_pointcloud = BKE_pointcloud_new_nomain(0); - BKE_object_eval_assign_data(object, &dummy_pointcloud->id, true); - object->runtime.geometry_set_eval = new GeometrySet(geometry_set); + const bool eval_is_owned = pointcloud_eval != pointcloud; + BKE_object_eval_assign_data(object, &pointcloud_eval->id, eval_is_owned); + object->runtime.geometry_set_eval = new GeometrySet(std::move(geometry_set)); } /* Draw Cache */ diff --git a/source/blender/blenkernel/intern/preferences.c b/source/blender/blenkernel/intern/preferences.c new file mode 100644 index 00000000000..8dcf6de164a --- /dev/null +++ b/source/blender/blenkernel/intern/preferences.c @@ -0,0 +1,119 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup bke + * + * User defined asset library API. + */ + +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" +#include "BLI_path_util.h" +#include "BLI_string.h" +#include "BLI_string_utf8.h" +#include "BLI_string_utils.h" + +#include "BKE_appdir.h" +#include "BKE_preferences.h" + +#include "BLT_translation.h" + +#include "DNA_userdef_types.h" + +#define U BLI_STATIC_ASSERT(false, "Global 'U' not allowed, only use arguments passed in!") + +/* -------------------------------------------------------------------- */ +/** \name Asset Libraries + * \{ */ + +bUserAssetLibrary *BKE_preferences_asset_library_add(UserDef *userdef, + const char *name, + const char *path) +{ + bUserAssetLibrary *library = MEM_callocN(sizeof(*library), "bUserAssetLibrary"); + + BLI_addtail(&userdef->asset_libraries, library); + + if (name) { + BKE_preferences_asset_library_name_set(userdef, library, name); + } + if (path) { + BLI_strncpy(library->path, path, sizeof(library->path)); + } + + return library; +} + +void BKE_preferences_asset_library_name_set(UserDef *userdef, + bUserAssetLibrary *library, + const char *name) +{ + BLI_strncpy_utf8(library->name, name, sizeof(library->name)); + BLI_uniquename(&userdef->asset_libraries, + library, + name, + '.', + offsetof(bUserAssetLibrary, name), + sizeof(library->name)); +} + +/** + * Unlink and free a library preference member. + * \note Free's \a library itself. + */ +void BKE_preferences_asset_library_remove(UserDef *userdef, bUserAssetLibrary *library) +{ + BLI_freelinkN(&userdef->asset_libraries, library); +} + +bUserAssetLibrary *BKE_preferences_asset_library_find_from_index(const UserDef *userdef, int index) +{ + return BLI_findlink(&userdef->asset_libraries, index); +} + +bUserAssetLibrary *BKE_preferences_asset_library_find_from_name(const UserDef *userdef, + const char *name) +{ + return BLI_findstring(&userdef->asset_libraries, name, offsetof(bUserAssetLibrary, name)); +} + +int BKE_preferences_asset_library_get_index(const UserDef *userdef, + const bUserAssetLibrary *library) +{ + return BLI_findindex(&userdef->asset_libraries, library); +} + +void BKE_preferences_asset_library_default_add(UserDef *userdef) +{ + char documents_path[FILE_MAXDIR]; + + /* No home or documents path found, not much we can do. */ + if (!BKE_appdir_folder_documents(documents_path) || !documents_path[0]) { + return; + } + + bUserAssetLibrary *library = BKE_preferences_asset_library_add(userdef, DATA_("Default"), NULL); + + /* Add new "Default" library under '[doc_path]/Blender/Assets'. */ + BLI_path_join( + library->path, sizeof(library->path), documents_path, N_("Blender"), N_("Assets"), NULL); +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 68b9589ce95..ccaab0a271e 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -37,6 +37,7 @@ #include "DNA_gpencil_types.h" #include "DNA_linestyle_types.h" #include "DNA_mask_types.h" +#include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_node_types.h" #include "DNA_object_types.h" @@ -47,6 +48,7 @@ #include "DNA_sound_types.h" #include "DNA_space_types.h" #include "DNA_text_types.h" +#include "DNA_vfont_types.h" #include "DNA_view3d_types.h" #include "DNA_windowmanager_types.h" #include "DNA_workspace_types.h" @@ -107,7 +109,13 @@ #include "RE_engine.h" +#include "SEQ_edit.h" +#include "SEQ_iterator.h" +#include "SEQ_modifier.h" +#include "SEQ_proxy.h" +#include "SEQ_relations.h" #include "SEQ_sequencer.h" +#include "SEQ_sound.h" #include "BLO_read_write.h" @@ -220,6 +228,7 @@ static void scene_init_data(ID *id) /* Curve Profile */ scene->toolsettings->custom_bevel_profile_preset = BKE_curveprofile_add(PROF_PRESET_LINE); + scene->toolsettings->sequencer_tool_settings = SEQ_tool_settings_init(); for (size_t i = 0; i < ARRAY_SIZE(scene->orientation_slots); i++) { scene->orientation_slots[i].index_custom = -1; @@ -337,7 +346,7 @@ static void scene_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int if (scene_src->ed) { scene_dst->ed = MEM_callocN(sizeof(*scene_dst->ed), __func__); scene_dst->ed->seqbasep = &scene_dst->ed->seqbase; - BKE_sequence_base_dupli_recursive(scene_src, + SEQ_sequence_base_dupli_recursive(scene_src, scene_dst, &scene_dst->ed->seqbase, &scene_src->ed->seqbase, @@ -372,7 +381,7 @@ static void scene_free_data(ID *id) Scene *scene = (Scene *)id; const bool do_id_user = false; - BKE_sequencer_editing_free(scene, do_id_user); + SEQ_editing_free(scene, do_id_user); BKE_keyingsets_free(&scene->keyingsets); @@ -860,6 +869,9 @@ static void scene_blend_write(BlendWriter *writer, ID *id, const void *id_addres if (tos->custom_bevel_profile_preset) { BKE_curveprofile_blend_write(writer, tos->custom_bevel_profile_preset); } + if (tos->sequencer_tool_settings) { + BLO_write_struct(writer, SequencerToolSettings, tos->sequencer_tool_settings); + } BKE_paint_blend_write(writer, &tos->imapaint.paint); @@ -942,7 +954,7 @@ static void scene_blend_write(BlendWriter *writer, ID *id, const void *id_addres IDP_BlendWrite(writer, seq->prop); } - BKE_sequence_modifier_blend_write(writer, &seq->modifiers); + SEQ_modifier_blend_write(writer, &seq->modifiers); } SEQ_ALL_END; @@ -1119,6 +1131,8 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id) if (sce->toolsettings->custom_bevel_profile_preset) { BKE_curveprofile_blend_read(reader, sce->toolsettings->custom_bevel_profile_preset); } + + BLO_read_data_address(reader, &sce->toolsettings->sequencer_tool_settings); } if (sce->ed) { @@ -1137,7 +1151,7 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id) Sequence *seq; SEQ_ALL_BEGIN (ed, seq) { /* Do as early as possible, so that other parts of reading can rely on valid session UUID. */ - BKE_sequence_session_uuid_generate(seq); + SEQ_relations_session_uuid_generate(seq); BLO_read_data_address(reader, &seq->seq1); BLO_read_data_address(reader, &seq->seq2); @@ -1196,7 +1210,7 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id) BLO_read_data_address(reader, &seq->strip->color_balance); } - BKE_sequence_modifier_blend_read_data(reader, &seq->modifiers); + SEQ_modifier_blend_read_data(reader, &seq->modifiers); } SEQ_ALL_END; @@ -1485,7 +1499,7 @@ static void scene_blend_read_lib(BlendLibReader *reader, ID *id) } BLI_listbase_clear(&seq->anims); - BKE_sequence_modifier_blend_read_lib(reader, sce, &seq->modifiers); + SEQ_modifier_blend_read_lib(reader, sce, &seq->modifiers); } SEQ_ALL_END; @@ -1790,6 +1804,8 @@ ToolSettings *BKE_toolsettings_copy(ToolSettings *toolsettings, const int flag) ts->gp_sculpt.cur_primitive = BKE_curvemapping_copy(ts->gp_sculpt.cur_primitive); ts->custom_bevel_profile_preset = BKE_curveprofile_copy(ts->custom_bevel_profile_preset); + + ts->sequencer_tool_settings = SEQ_tool_settings_copy(ts->sequencer_tool_settings); return ts; } @@ -1848,6 +1864,10 @@ void BKE_toolsettings_free(ToolSettings *toolsettings) BKE_curveprofile_free(toolsettings->custom_bevel_profile_preset); } + if (toolsettings->sequencer_tool_settings) { + SEQ_tool_settings_free(toolsettings->sequencer_tool_settings); + } + MEM_freeN(toolsettings); } @@ -1999,7 +2019,7 @@ Scene *BKE_scene_duplicate(Main *bmain, Scene *sce, eSceneCopyMethod type) /* Remove sequencer if not full copy */ /* XXX Why in Hell? :/ */ remove_sequencer_fcurves(sce_copy); - BKE_sequencer_editing_free(sce_copy, true); + SEQ_editing_free(sce_copy, true); } return sce_copy; @@ -3720,6 +3740,6 @@ void BKE_scene_eval_sequencer_sequences(Depsgraph *depsgraph, Scene *scene) } } SEQ_ALL_END; - BKE_sequencer_update_muting(scene->ed); - BKE_sequencer_update_sound_bounds_all(scene); + SEQ_edit_update_muting(scene->ed); + SEQ_sound_update_bounds_all(scene); } diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 355db8f0d60..52c41c9fd05 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -34,6 +34,7 @@ #include "MEM_guardedalloc.h" +#include "DNA_collection_types.h" #include "DNA_defaults.h" #include "DNA_gpencil_types.h" #include "DNA_mask_types.h" @@ -1265,6 +1266,9 @@ static void write_area_regions(BlendWriter *writer, ScrArea *area) if (sfile->params) { BLO_write_struct(writer, FileSelectParams, sfile->params); } + if (sfile->asset_params) { + BLO_write_struct(writer, FileAssetSelectParams, sfile->asset_params); + } } else if (sl->spacetype == SPACE_SEQ) { BLO_write_struct(writer, SpaceSeq, sl); @@ -1662,11 +1666,14 @@ static void direct_link_area(BlendDataReader *reader, ScrArea *area) * plus, it isn't saved to files yet! */ sfile->folders_prev = sfile->folders_next = NULL; + BLI_listbase_clear(&sfile->folder_histories); sfile->files = NULL; sfile->layout = NULL; sfile->op = NULL; sfile->previews_timer = NULL; + sfile->tags = 0; BLO_read_data_address(reader, &sfile->params); + BLO_read_data_address(reader, &sfile->asset_params); } else if (sl->spacetype == SPACE_CLIP) { SpaceClip *sclip = (SpaceClip *)sl; @@ -1750,8 +1757,11 @@ void BKE_screen_area_blend_read_lib(BlendLibReader *reader, ID *parent_id, ScrAr } break; } - case SPACE_FILE: + case SPACE_FILE: { + SpaceFile *sfile = (SpaceFile *)sl; + sfile->tags |= FILE_TAG_REBUILD_MAIN_FILES; break; + } case SPACE_ACTION: { SpaceAction *saction = (SpaceAction *)sl; bDopeSheet *ads = &saction->ads; diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index 25d812884bc..736acd76dfd 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -52,6 +52,7 @@ #include "DNA_lattice_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "DNA_object_force_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index 8b66b1fc628..78729fb9261 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -68,6 +68,7 @@ #include "BLO_read_write.h" #include "SEQ_sequencer.h" +#include "SEQ_sound.h" static void sound_free_audio(bSound *sound); @@ -135,13 +136,19 @@ static void sound_foreach_cache(ID *id, static void sound_blend_write(BlendWriter *writer, ID *id, const void *id_address) { bSound *sound = (bSound *)id; - if (sound->id.us > 0 || BLO_write_is_undo(writer)) { + const bool is_undo = BLO_write_is_undo(writer); + if (sound->id.us > 0 || is_undo) { /* Clean up, important in undo case to reduce false detection of changed datablocks. */ sound->tags = 0; sound->handle = NULL; sound->playback_handle = NULL; sound->spinlock = NULL; + /* Do not store packed files in case this is a library override ID. */ + if (ID_IS_OVERRIDE_LIBRARY(sound) && !is_undo) { + sound->packedfile = NULL; + } + /* write LibData */ BLO_write_id_struct(writer, bSound, id_address, &sound->id); BKE_id_blend_write(writer, &sound->id); @@ -677,7 +684,7 @@ void BKE_sound_update_fps(Main *bmain, Scene *scene) AUD_Sequence_setFPS(scene->sound_scene, FPS); } - BKE_sequencer_refresh_sound_length(bmain, scene); + SEQ_sound_update_length(bmain, scene); } void BKE_sound_update_scene_listener(Scene *scene) @@ -819,7 +826,7 @@ void BKE_sound_update_sequencer(Main *main, bSound *sound) Scene *scene; for (scene = main->scenes.first; scene; scene = scene->id.next) { - BKE_sequencer_update_sound(scene, sound); + SEQ_sound_update(scene, sound); } } diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 93795af7cd7..9ef2e818293 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -459,12 +459,14 @@ bool BKE_text_reload(Text *text) return true; } -/** Load a text file. +/** + * Load a text file. * - * \param is_internal If \a true, this text data-block only exists in memory, not as a file on - * disk. + * \param is_internal: If \a true, this text data-block only exists in memory, + * not as a file on disk. * - * \note: text data-blocks have no user by default, only the 'real user' flag. */ + * \note text data-blocks have no user by default, only the 'real user' flag. + */ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const bool is_internal) { unsigned char *buffer; @@ -520,7 +522,8 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const /** Load a text file. * - * \note: text data-blocks have no user by default, only the 'real user' flag. */ + * \note Text data-blocks have no user by default, only the 'real user' flag. + */ Text *BKE_text_load(Main *bmain, const char *file, const char *relpath) { return BKE_text_load_ex(bmain, file, relpath, false); diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c index e083f7ceec0..e5f9d59270e 100644 --- a/source/blender/blenkernel/intern/tracking.c +++ b/source/blender/blenkernel/intern/tracking.c @@ -3138,13 +3138,13 @@ void BKE_tracking_get_rna_path_for_track(const struct MovieTracking *tracking, { MovieTrackingObject *object = BKE_tracking_find_object_for_track(tracking, track); char track_name_esc[MAX_NAME * 2]; - BLI_strescape(track_name_esc, track->name, sizeof(track_name_esc)); + BLI_str_escape(track_name_esc, track->name, sizeof(track_name_esc)); if (object == NULL) { BLI_snprintf(rna_path, rna_path_len, "tracking.tracks[\"%s\"]", track_name_esc); } else { char object_name_esc[MAX_NAME * 2]; - BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc)); + BLI_str_escape(object_name_esc, object->name, sizeof(object_name_esc)); BLI_snprintf(rna_path, rna_path_len, "tracking.objects[\"%s\"].tracks[\"%s\"]", @@ -3164,7 +3164,7 @@ void BKE_tracking_get_rna_path_prefix_for_track(const struct MovieTracking *trac } else { char object_name_esc[MAX_NAME * 2]; - BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc)); + BLI_str_escape(object_name_esc, object->name, sizeof(object_name_esc)); BLI_snprintf(rna_path, rna_path_len, "tracking.objects[\"%s\"]", object_name_esc); } } @@ -3176,13 +3176,13 @@ void BKE_tracking_get_rna_path_for_plane_track(const struct MovieTracking *track { MovieTrackingObject *object = BKE_tracking_find_object_for_plane_track(tracking, plane_track); char track_name_esc[MAX_NAME * 2]; - BLI_strescape(track_name_esc, plane_track->name, sizeof(track_name_esc)); + BLI_str_escape(track_name_esc, plane_track->name, sizeof(track_name_esc)); if (object == NULL) { BLI_snprintf(rna_path, rna_path_len, "tracking.plane_tracks[\"%s\"]", track_name_esc); } else { char object_name_esc[MAX_NAME * 2]; - BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc)); + BLI_str_escape(object_name_esc, object->name, sizeof(object_name_esc)); BLI_snprintf(rna_path, rna_path_len, "tracking.objects[\"%s\"].plane_tracks[\"%s\"]", @@ -3203,7 +3203,7 @@ void BKE_tracking_get_rna_path_prefix_for_plane_track( } else { char object_name_esc[MAX_NAME * 2]; - BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc)); + BLI_str_escape(object_name_esc, object->name, sizeof(object_name_esc)); BLI_snprintf(rna_path, rna_path_len, "tracking.objects[\"%s\"].plane_tracks", object_name_esc); } } diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc index 11aa9597740..67727d87161 100644 --- a/source/blender/blenkernel/intern/volume.cc +++ b/source/blender/blenkernel/intern/volume.cc @@ -561,10 +561,16 @@ static void volume_foreach_cache(ID *id, static void volume_blend_write(BlendWriter *writer, ID *id, const void *id_address) { Volume *volume = (Volume *)id; - if (volume->id.us > 0 || BLO_write_is_undo(writer)) { + const bool is_undo = BLO_write_is_undo(writer); + if (volume->id.us > 0 || is_undo) { /* Clean up, important in undo case to reduce false detection of changed datablocks. */ volume->runtime.grids = nullptr; + /* Do not store packed files in case this is a library override ID. */ + if (ID_IS_OVERRIDE_LIBRARY(volume) && !is_undo) { + volume->packedfile = nullptr; + } + /* write LibData */ BLO_write_id_struct(writer, Volume, id_address, &volume->id); BKE_id_blend_write(writer, &volume->id); diff --git a/source/blender/blenkernel/particle_private.h b/source/blender/blenkernel/particle_private.h index 33277d1caac..1c183aab3b7 100644 --- a/source/blender/blenkernel/particle_private.h +++ b/source/blender/blenkernel/particle_private.h @@ -27,6 +27,8 @@ extern "C" { #endif +struct CurveMapping; + typedef struct ParticleChildModifierContext { ParticleThreadContext *thread_ctx; ParticleSimulationData *sim; @@ -62,7 +64,7 @@ float do_clump(ParticleKey *state, float pa_clump, bool use_clump_noise, float clump_noise_size, - CurveMapping *clumpcurve); + struct CurveMapping *clumpcurve); void do_child_modifiers(const ParticleChildModifierContext *modifier_ctx, float mat[4][4], ParticleKey *state, diff --git a/source/blender/blenlib/BLI_array.hh b/source/blender/blenlib/BLI_array.hh index 8a7dcb7ffaa..284d62fb876 100644 --- a/source/blender/blenlib/BLI_array.hh +++ b/source/blender/blenlib/BLI_array.hh @@ -220,13 +220,13 @@ class Array { return MutableSpan<T>(data_, size_); } - template<typename U, typename std::enable_if_t<is_convertible_pointer_v<T, U>> * = nullptr> + template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<T, U>> * = nullptr> operator Span<U>() const { return Span<U>(data_, size_); } - template<typename U, typename std::enable_if_t<is_convertible_pointer_v<T, U>> * = nullptr> + template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<T, U>> * = nullptr> operator MutableSpan<U>() { return MutableSpan<U>(data_, size_); diff --git a/source/blender/blenlib/BLI_hash.h b/source/blender/blenlib/BLI_hash.h index c2be416ef5f..d687e805323 100644 --- a/source/blender/blenlib/BLI_hash.h +++ b/source/blender/blenlib/BLI_hash.h @@ -26,35 +26,59 @@ extern "C" { #endif -BLI_INLINE unsigned int BLI_hash_int_2d(unsigned int kx, unsigned int ky) -{ +/** + * Jenkins Lookup3 Hash Functions. + * Source: http://burtleburtle.net/bob/c/lookup3.c + */ + #define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k)))) +#define final(a, b, c) \ + { \ + c ^= b; \ + c -= rot(b, 14); \ + a ^= c; \ + a -= rot(c, 11); \ + b ^= a; \ + b -= rot(a, 25); \ + c ^= b; \ + c -= rot(b, 16); \ + a ^= c; \ + a -= rot(c, 4); \ + b ^= a; \ + b -= rot(a, 14); \ + c ^= b; \ + c -= rot(b, 24); \ + } \ + ((void)0) + +BLI_INLINE unsigned int BLI_hash_int_3d(unsigned int kx, unsigned int ky, unsigned int kz) +{ + unsigned int a, b, c; + a = b = c = 0xdeadbeef + (3 << 2) + 13; + + c += kz; + b += ky; + a += kx; + final(a, b, c); + + return c; +} +BLI_INLINE unsigned int BLI_hash_int_2d(unsigned int kx, unsigned int ky) +{ unsigned int a, b, c; a = b = c = 0xdeadbeef + (2 << 2) + 13; a += kx; b += ky; - c ^= b; - c -= rot(b, 14); - a ^= c; - a -= rot(c, 11); - b ^= a; - b -= rot(a, 25); - c ^= b; - c -= rot(b, 16); - a ^= c; - a -= rot(c, 4); - b ^= a; - b -= rot(a, 14); - c ^= b; - c -= rot(b, 24); + final(a, b, c); return c; +} +#undef final #undef rot -} BLI_INLINE unsigned int BLI_hash_string(const char *str) { diff --git a/source/blender/blenlib/BLI_index_range.hh b/source/blender/blenlib/BLI_index_range.hh index 2b060c986cd..4121542c887 100644 --- a/source/blender/blenlib/BLI_index_range.hh +++ b/source/blender/blenlib/BLI_index_range.hh @@ -73,21 +73,22 @@ class IndexRange { int64_t size_ = 0; public: - IndexRange() = default; + constexpr IndexRange() = default; - explicit IndexRange(int64_t size) : start_(0), size_(size) + constexpr explicit IndexRange(int64_t size) : start_(0), size_(size) { BLI_assert(size >= 0); } - IndexRange(int64_t start, int64_t size) : start_(start), size_(size) + constexpr IndexRange(int64_t start, int64_t size) : start_(start), size_(size) { BLI_assert(start >= 0); BLI_assert(size >= 0); } template<typename T> - IndexRange(const tbb::blocked_range<T> &range) : start_(range.begin()), size_(range.size()) + constexpr IndexRange(const tbb::blocked_range<T> &range) + : start_(range.begin()), size_(range.size()) { } @@ -96,33 +97,33 @@ class IndexRange { int64_t current_; public: - Iterator(int64_t current) : current_(current) + constexpr Iterator(int64_t current) : current_(current) { } - Iterator &operator++() + constexpr Iterator &operator++() { current_++; return *this; } - bool operator!=(const Iterator &iterator) const + constexpr bool operator!=(const Iterator &iterator) const { return current_ != iterator.current_; } - int64_t operator*() const + constexpr int64_t operator*() const { return current_; } }; - Iterator begin() const + constexpr Iterator begin() const { return Iterator(start_); } - Iterator end() const + constexpr Iterator end() const { return Iterator(start_ + size_); } @@ -130,7 +131,7 @@ class IndexRange { /** * Access an element in the range. */ - int64_t operator[](int64_t index) const + constexpr int64_t operator[](int64_t index) const { BLI_assert(index >= 0); BLI_assert(index < this->size()); @@ -140,7 +141,7 @@ class IndexRange { /** * Two ranges compare equal when they contain the same numbers. */ - friend bool operator==(IndexRange a, IndexRange b) + constexpr friend bool operator==(IndexRange a, IndexRange b) { return (a.size_ == b.size_) && (a.start_ == b.start_ || a.size_ == 0); } @@ -148,7 +149,7 @@ class IndexRange { /** * Get the amount of numbers in the range. */ - int64_t size() const + constexpr int64_t size() const { return size_; } @@ -156,7 +157,7 @@ class IndexRange { /** * Create a new range starting at the end of the current one. */ - IndexRange after(int64_t n) const + constexpr IndexRange after(int64_t n) const { BLI_assert(n >= 0); return IndexRange(start_ + size_, n); @@ -165,7 +166,7 @@ class IndexRange { /** * Create a new range that ends at the start of the current one. */ - IndexRange before(int64_t n) const + constexpr IndexRange before(int64_t n) const { BLI_assert(n >= 0); return IndexRange(start_ - n, n); @@ -175,7 +176,7 @@ class IndexRange { * Get the first element in the range. * Asserts when the range is empty. */ - int64_t first() const + constexpr int64_t first() const { BLI_assert(this->size() > 0); return start_; @@ -185,7 +186,7 @@ class IndexRange { * Get the last element in the range. * Asserts when the range is empty. */ - int64_t last() const + constexpr int64_t last() const { BLI_assert(this->size() > 0); return start_ + size_ - 1; @@ -194,7 +195,7 @@ class IndexRange { /** * Get the element one after the end. The returned value is undefined when the range is empty. */ - int64_t one_after_last() const + constexpr int64_t one_after_last() const { return start_ + size_; } @@ -202,7 +203,7 @@ class IndexRange { /** * Get the first element in the range. The returned value is undefined when the range is empty. */ - int64_t start() const + constexpr int64_t start() const { return start_; } @@ -210,7 +211,7 @@ class IndexRange { /** * Returns true when the range contains a certain number, otherwise false. */ - bool contains(int64_t value) const + constexpr bool contains(int64_t value) const { return value >= start_ && value < start_ + size_; } @@ -218,7 +219,7 @@ class IndexRange { /** * Returns a new range, that contains a sub-interval of the current one. */ - IndexRange slice(int64_t start, int64_t size) const + constexpr IndexRange slice(int64_t start, int64_t size) const { BLI_assert(start >= 0); BLI_assert(size >= 0); @@ -226,7 +227,7 @@ class IndexRange { BLI_assert(new_start + size <= start_ + size_ || size == 0); return IndexRange(new_start, size); } - IndexRange slice(IndexRange range) const + constexpr IndexRange slice(IndexRange range) const { return this->slice(range.start(), range.size()); } diff --git a/source/blender/blenlib/BLI_inplace_priority_queue.hh b/source/blender/blenlib/BLI_inplace_priority_queue.hh new file mode 100644 index 00000000000..e76cb8504a3 --- /dev/null +++ b/source/blender/blenlib/BLI_inplace_priority_queue.hh @@ -0,0 +1,304 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include "BLI_array.hh" +#include "BLI_dot_export.hh" + +namespace blender { + +/** + * An InplacePriorityQueue adds priority queue functionality to an existing array. The underlying + * array is not changed. Instead, the priority queue maintains indices into the original array. + * + * The priority queue provides efficient access to the element in order of their priorities. + * + * When a priority changes, the priority queue has to be informed using one of the following + * methods: #priority_decreased, #priority_increased or #priority_changed. + */ +template< + /* Type of the elements in the underlying array. */ + typename T, + /* Binary function that takes two `const T &` inputs and returns true, when the first input has + greater priority than the second. */ + typename FirstHasHigherPriority = std::greater<T>> +class InplacePriorityQueue { + private: + /* Underlying array the priority queue is built upon. This is a span instead of a mutable span, + * because this data structure never changes the values itself. */ + Span<T> data_; + /* Maps indices from the heap (binary tree in array format) to indices of the underlying/original + * array. */ + Array<int64_t> heap_to_orig_; + /* This is the inversion of the above mapping. */ + Array<int64_t> orig_to_heap_; + /* Number of elements that are currently in the priority queue. */ + int64_t heap_size_ = 0; + /* Function that can be changed to customize how the priority of two elements is compared. */ + FirstHasHigherPriority first_has_higher_priority_fn_; + + public: + /** + * Construct the priority queue on top of the data in the given span. + */ + InplacePriorityQueue(Span<T> data) + : data_(data), heap_to_orig_(data_.size()), orig_to_heap_(data_.size()) + { + for (const int64_t i : IndexRange(data_.size())) { + heap_to_orig_[i] = i; + orig_to_heap_[i] = i; + } + + this->rebuild(); + } + + /** + * Rebuilds the priority queue from the array that has been passed to the constructor. + */ + void rebuild() + { + const int final_heap_size = data_.size(); + if (final_heap_size > 1) { + for (int64_t i = this->get_parent(final_heap_size - 1); i >= 0; i--) { + this->heapify(i, final_heap_size); + } + } + heap_size_ = final_heap_size; + } + + /** + * Returns the number of elements in the priority queue. + * This is less or equal than the size of the underlying array. + */ + int64_t size() const + { + return heap_size_; + } + + /** + * Returns true, when the priority queue contains no elements. If this returns true, #peek and + * #pop must not be used. + */ + bool is_empty() const + { + return heap_size_ == 0; + } + + /** + * Get the element with the highest priority in the priority queue. + * The returned reference is const, because the priority queue has read-only access to the + * underlying data. If you need a mutable reference, use #peek_index instead. + */ + const T &peek() const + { + return data_[this->peek_index()]; + } + + /** + * Get the element with the highest priority in the priority queue and remove it. + * The returned reference is const, because the priority queue has read-only access to the + * underlying data. If you need a mutable reference, use #pop_index instead. + */ + const T &pop() + { + return data_[this->pop_index()]; + } + + /** + * Get the index of the element with the highest priority in the priority queue. + */ + int64_t peek_index() const + { + BLI_assert(!this->is_empty()); + return heap_to_orig_[0]; + } + + /** + * Get the index of the element with the highest priority in the priority queue and remove it. + */ + int64_t pop_index() + { + BLI_assert(!this->is_empty()); + const int64_t top_index_orig = heap_to_orig_[0]; + heap_size_--; + if (heap_size_ > 1) { + this->swap_indices(0, heap_size_); + this->heapify(0, heap_size_); + } + return top_index_orig; + } + + /** + * Inform the priority queue that the priority of the element at the given index has been + * decreased. + */ + void priority_decreased(const int64_t index) + { + const int64_t heap_index = orig_to_heap_[index]; + if (heap_index >= heap_size_) { + /* This element is not in the queue currently. */ + return; + } + this->heapify(heap_index, heap_size_); + } + + /** + * Inform the priority queue that the priority of the element at the given index has been + * increased. + */ + void priority_increased(const int64_t index) + { + int64_t current = orig_to_heap_[index]; + if (current >= heap_size_) { + /* This element is not in the queue currently. */ + return; + } + while (true) { + if (current == 0) { + break; + } + const int64_t parent = this->get_parent(current); + if (this->first_has_higher_priority(parent, current)) { + break; + } + this->swap_indices(current, parent); + current = parent; + } + } + + /** + * Inform the priority queue that the priority of the element at the given index has been + * changed. + */ + void priority_changed(const int64_t index) + { + this->priority_increased(index); + this->priority_decreased(index); + } + + /** + * Returns the indices of all elements that are in the priority queue. + * There are no guarantees about the order of indices. + */ + Span<int64_t> active_indices() const + { + return heap_to_orig_.as_span().take_front(heap_size_); + } + + /** + * Returns the indices of all elements that are not in the priority queue. + * The indices are in reverse order of their removal from the queue. + * I.e. the index that has been removed last, comes first. + */ + Span<int64_t> inactive_indices() const + { + return heap_to_orig_.as_span().drop_front(heap_size_); + } + + /** + * Returns the concatenation of the active and inactive indices. + */ + Span<int64_t> all_indices() const + { + return heap_to_orig_; + } + + /** + * Return the heap used by the priority queue as dot graph string. + * This exists for debugging purposes. + */ + std::string to_dot() const + { + return this->partial_to_dot(heap_size_); + } + + private: + bool first_has_higher_priority(const int64_t a, const int64_t b) + { + const T &value_a = data_[heap_to_orig_[a]]; + const T &value_b = data_[heap_to_orig_[b]]; + return first_has_higher_priority_fn_(value_a, value_b); + } + + void swap_indices(const int64_t a, const int64_t b) + { + std::swap(heap_to_orig_[a], heap_to_orig_[b]); + orig_to_heap_[heap_to_orig_[a]] = a; + orig_to_heap_[heap_to_orig_[b]] = b; + } + + void heapify(const int64_t parent, const int64_t heap_size) + { + int64_t max_index = parent; + const int left = this->get_left(parent); + const int right = this->get_right(parent); + if (left < heap_size && this->first_has_higher_priority(left, max_index)) { + max_index = left; + } + if (right < heap_size && this->first_has_higher_priority(right, max_index)) { + max_index = right; + } + if (max_index != parent) { + this->swap_indices(parent, max_index); + this->heapify(max_index, heap_size); + } + if (left < heap_size) { + BLI_assert(!this->first_has_higher_priority(left, parent)); + } + if (right < heap_size) { + BLI_assert(!this->first_has_higher_priority(right, parent)); + } + } + + int64_t get_parent(const int64_t child) const + { + BLI_assert(child > 0); + return (child - 1) / 2; + } + + int64_t get_left(const int64_t parent) const + { + return parent * 2 + 1; + } + + int64_t get_right(const int64_t parent) const + { + return parent * 2 + 2; + } + + std::string partial_to_dot(const int size) const + { + dot::DirectedGraph digraph; + Array<dot::Node *> dot_nodes(size); + for (const int i : IndexRange(size)) { + std::stringstream ss; + ss << data_[heap_to_orig_[i]]; + const std::string name = ss.str(); + dot::Node &node = digraph.new_node(name); + node.set_shape(dot::Attr_shape::Rectangle); + node.attributes.set("ordering", "out"); + dot_nodes[i] = &node; + if (i > 0) { + const int64_t parent = this->get_parent(i); + digraph.new_edge(*dot_nodes[parent], node); + } + } + return digraph.to_dot_string(); + } +}; + +} // namespace blender diff --git a/source/blender/blenlib/BLI_kdopbvh.h b/source/blender/blenlib/BLI_kdopbvh.h index c34b71a60f9..5e0ea4f2a99 100644 --- a/source/blender/blenlib/BLI_kdopbvh.h +++ b/source/blender/blenlib/BLI_kdopbvh.h @@ -178,6 +178,7 @@ int *BLI_bvhtree_intersect_plane(BVHTree *tree, float plane[4], uint *r_intersec int BLI_bvhtree_get_len(const BVHTree *tree); int BLI_bvhtree_get_tree_type(const BVHTree *tree); float BLI_bvhtree_get_epsilon(const BVHTree *tree); +void BLI_bvhtree_get_bounding_box(BVHTree *tree, float r_bb_min[3], float r_bb_max[3]); /* find nearest node to the given coordinates * (if nearest is given it will only search nodes where diff --git a/source/blender/blenlib/BLI_memory_utils.hh b/source/blender/blenlib/BLI_memory_utils.hh index 49076bb1aae..b3b6855089e 100644 --- a/source/blender/blenlib/BLI_memory_utils.hh +++ b/source/blender/blenlib/BLI_memory_utils.hh @@ -428,6 +428,25 @@ inline constexpr bool is_convertible_pointer_v = std::is_convertible_v<From, To> &&std::is_pointer_v<From> &&std::is_pointer_v<To>; /** + * Helper variable that checks if a Span<From> can be converted to Span<To> safely, whereby From + * and To are pointers. Adding const and casting to a void pointer is allowed. + * Casting up and down a class hierarchy generally is not allowed, because this might change the + * pointer under some circumstances. + */ +template<typename From, typename To> +inline constexpr bool is_span_convertible_pointer_v = + /* Make sure we are working with pointers. */ + std::is_pointer_v<From> &&std::is_pointer_v<To> && + (/* No casting is necessary when both types are the same. */ + std::is_same_v<From, To> || + /* Allow adding const to the underlying type. */ + std::is_same_v<const std::remove_pointer_t<From>, std::remove_pointer_t<To>> || + /* Allow casting non-const pointers to void pointers. */ + (!std::is_const_v<std::remove_pointer_t<From>> && std::is_same_v<To, void *>) || + /* Allow casting any pointer to const void pointers. */ + std::is_same_v<To, const void *>); + +/** * Inline buffers for small-object-optimization should be disable by default. Otherwise we might * get large unexpected allocations on the stack. */ diff --git a/source/blender/blenlib/BLI_span.hh b/source/blender/blenlib/BLI_span.hh index 5b4d2769f57..8011b2f9abc 100644 --- a/source/blender/blenlib/BLI_span.hh +++ b/source/blender/blenlib/BLI_span.hh @@ -93,15 +93,15 @@ template<typename T> class Span { /** * Create a reference to an empty array. */ - Span() = default; + constexpr Span() = default; - Span(const T *start, int64_t size) : data_(start), size_(size) + constexpr Span(const T *start, int64_t size) : data_(start), size_(size) { BLI_assert(size >= 0); } - template<typename U, typename std::enable_if_t<is_convertible_pointer_v<U, T>> * = nullptr> - Span(const U *start, int64_t size) : data_(static_cast<const T *>(start)), size_(size) + template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<U, T>> * = nullptr> + constexpr Span(const U *start, int64_t size) : data_(static_cast<const T *>(start)), size_(size) { BLI_assert(size >= 0); } @@ -117,16 +117,17 @@ template<typename T> class Span { * Span<int> span = {1, 2, 3, 4}; * call_function_with_array(span); */ - Span(const std::initializer_list<T> &list) + constexpr Span(const std::initializer_list<T> &list) : Span(list.begin(), static_cast<int64_t>(list.size())) { } - Span(const std::vector<T> &vector) : Span(vector.data(), static_cast<int64_t>(vector.size())) + constexpr Span(const std::vector<T> &vector) + : Span(vector.data(), static_cast<int64_t>(vector.size())) { } - template<std::size_t N> Span(const std::array<T, N> &array) : Span(array.data(), N) + template<std::size_t N> constexpr Span(const std::array<T, N> &array) : Span(array.data(), N) { } @@ -134,8 +135,9 @@ template<typename T> class Span { * Support implicit conversions like the ones below: * Span<T *> -> Span<const T *> */ - template<typename U, typename std::enable_if_t<is_convertible_pointer_v<U, T>> * = nullptr> - Span(Span<U> array) : data_(static_cast<const T *>(array.data())), size_(array.size()) + + template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<U, T>> * = nullptr> + constexpr Span(Span<U> array) : data_(static_cast<const T *>(array.data())), size_(array.size()) { } @@ -143,7 +145,7 @@ template<typename T> class Span { * Returns a contiguous part of the array. This invokes undefined behavior when the slice does * not stay within the bounds of the array. */ - Span slice(int64_t start, int64_t size) const + constexpr Span slice(int64_t start, int64_t size) const { BLI_assert(start >= 0); BLI_assert(size >= 0); @@ -151,7 +153,7 @@ template<typename T> class Span { return Span(data_ + start, size); } - Span slice(IndexRange range) const + constexpr Span slice(IndexRange range) const { return this->slice(range.start(), range.size()); } @@ -160,7 +162,7 @@ template<typename T> class Span { * Returns a new Span with n elements removed from the beginning. This invokes undefined * behavior when the array is too small. */ - Span drop_front(int64_t n) const + constexpr Span drop_front(int64_t n) const { BLI_assert(n >= 0); BLI_assert(n <= this->size()); @@ -171,7 +173,7 @@ template<typename T> class Span { * Returns a new Span with n elements removed from the beginning. This invokes undefined * behavior when the array is too small. */ - Span drop_back(int64_t n) const + constexpr Span drop_back(int64_t n) const { BLI_assert(n >= 0); BLI_assert(n <= this->size()); @@ -182,7 +184,7 @@ template<typename T> class Span { * Returns a new Span that only contains the first n elements. This invokes undefined * behavior when the array is too small. */ - Span take_front(int64_t n) const + constexpr Span take_front(int64_t n) const { BLI_assert(n >= 0); BLI_assert(n <= this->size()); @@ -193,7 +195,7 @@ template<typename T> class Span { * Returns a new Span that only contains the last n elements. This invokes undefined * behavior when the array is too small. */ - Span take_back(int64_t n) const + constexpr Span take_back(int64_t n) const { BLI_assert(n >= 0); BLI_assert(n <= this->size()); @@ -204,25 +206,25 @@ template<typename T> class Span { * Returns the pointer to the beginning of the referenced array. This may be nullptr when the * size is zero. */ - const T *data() const + constexpr const T *data() const { return data_; } - const T *begin() const + constexpr const T *begin() const { return data_; } - const T *end() const + constexpr const T *end() const { return data_ + size_; } - std::reverse_iterator<const T *> rbegin() const + constexpr std::reverse_iterator<const T *> rbegin() const { return std::reverse_iterator<const T *>(this->end()); } - std::reverse_iterator<const T *> rend() const + constexpr std::reverse_iterator<const T *> rend() const { return std::reverse_iterator<const T *>(this->begin()); } @@ -231,7 +233,7 @@ template<typename T> class Span { * Access an element in the array. This invokes undefined behavior when the index is out of * bounds. */ - const T &operator[](int64_t index) const + constexpr const T &operator[](int64_t index) const { BLI_assert(index >= 0); BLI_assert(index < size_); @@ -241,7 +243,7 @@ template<typename T> class Span { /** * Returns the number of elements in the referenced array. */ - int64_t size() const + constexpr int64_t size() const { return size_; } @@ -249,7 +251,7 @@ template<typename T> class Span { /** * Returns true if the size is zero. */ - bool is_empty() const + constexpr bool is_empty() const { return size_ == 0; } @@ -257,7 +259,7 @@ template<typename T> class Span { /** * Returns the number of bytes referenced by this Span. */ - int64_t size_in_bytes() const + constexpr int64_t size_in_bytes() const { return sizeof(T) * size_; } @@ -266,7 +268,7 @@ template<typename T> class Span { * Does a linear search to see of the value is in the array. * Returns true if it is, otherwise false. */ - bool contains(const T &value) const + constexpr bool contains(const T &value) const { for (const T &element : *this) { if (element == value) { @@ -280,7 +282,7 @@ template<typename T> class Span { * Does a constant time check to see if the pointer points to a value in the referenced array. * Return true if it is, otherwise false. */ - bool contains_ptr(const T *ptr) const + constexpr bool contains_ptr(const T *ptr) const { return (this->begin() <= ptr) && (ptr < this->end()); } @@ -289,7 +291,7 @@ template<typename T> class Span { * Does a linear search to count how often the value is in the array. * Returns the number of occurrences. */ - int64_t count(const T &value) const + constexpr int64_t count(const T &value) const { int64_t counter = 0; for (const T &element : *this) { @@ -304,7 +306,7 @@ template<typename T> class Span { * Return a reference to the first element in the array. This invokes undefined behavior when the * array is empty. */ - const T &first() const + constexpr const T &first() const { BLI_assert(size_ > 0); return data_[0]; @@ -314,7 +316,7 @@ template<typename T> class Span { * Returns a reference to the last element in the array. This invokes undefined behavior when the * array is empty. */ - const T &last() const + constexpr const T &last() const { BLI_assert(size_ > 0); return data_[size_ - 1]; @@ -324,7 +326,7 @@ template<typename T> class Span { * Returns the element at the given index. If the index is out of range, return the fallback * value. */ - T get(int64_t index, const T &fallback) const + constexpr T get(int64_t index, const T &fallback) const { if (index < size_ && index >= 0) { return data_[index]; @@ -336,7 +338,7 @@ template<typename T> class Span { * Check if the array contains duplicates. Does a linear search for every element. So the total * running time is O(n^2). Only use this for small arrays. */ - bool has_duplicates__linear_search() const + constexpr bool has_duplicates__linear_search() const { /* The size should really be smaller than that. If it is not, the calling code should be * changed. */ @@ -358,7 +360,7 @@ template<typename T> class Span { * called on small arrays, because it has a running time of O(n*m) where n and m are the sizes of * the arrays. */ - bool intersects__linear_search(Span other) const + constexpr bool intersects__linear_search(Span other) const { /* The size should really be smaller than that. If it is not, the calling code should be * changed. */ @@ -377,7 +379,7 @@ template<typename T> class Span { * Returns the index of the first occurrence of the given value. This invokes undefined behavior * when the value is not in the array. */ - int64_t first_index(const T &search_value) const + constexpr int64_t first_index(const T &search_value) const { const int64_t index = this->first_index_try(search_value); BLI_assert(index >= 0); @@ -387,7 +389,7 @@ template<typename T> class Span { /** * Returns the index of the first occurrence of the given value or -1 if it does not exist. */ - int64_t first_index_try(const T &search_value) const + constexpr int64_t first_index_try(const T &search_value) const { for (int64_t i = 0; i < size_; i++) { if (data_[i] == search_value) { @@ -401,7 +403,7 @@ template<typename T> class Span { * Utility to make it more convenient to iterate over all indices that can be used with this * array. */ - IndexRange index_range() const + constexpr IndexRange index_range() const { return IndexRange(size_); } @@ -409,7 +411,7 @@ template<typename T> class Span { /** * Returns a new Span to the same underlying memory buffer. No conversions are done. */ - template<typename NewT> Span<NewT> cast() const + template<typename NewT> Span<NewT> constexpr cast() const { BLI_assert((size_ * sizeof(T)) % sizeof(NewT) == 0); int64_t new_size = size_ * sizeof(T) / sizeof(NewT); @@ -450,21 +452,22 @@ template<typename T> class MutableSpan { int64_t size_; public: - MutableSpan() = default; + constexpr MutableSpan() = default; - MutableSpan(T *start, const int64_t size) : data_(start), size_(size) + constexpr MutableSpan(T *start, const int64_t size) : data_(start), size_(size) { } - MutableSpan(std::vector<T> &vector) : MutableSpan(vector.data(), vector.size()) + constexpr MutableSpan(std::vector<T> &vector) : MutableSpan(vector.data(), vector.size()) { } - template<std::size_t N> MutableSpan(std::array<T, N> &array) : MutableSpan(array.data(), N) + template<std::size_t N> + constexpr MutableSpan(std::array<T, N> &array) : MutableSpan(array.data(), N) { } - operator Span<T>() const + constexpr operator Span<T>() const { return Span<T>(data_, size_); } @@ -472,7 +475,7 @@ template<typename T> class MutableSpan { /** * Returns the number of elements in the array. */ - int64_t size() const + constexpr int64_t size() const { return size_; } @@ -480,7 +483,7 @@ template<typename T> class MutableSpan { /** * Replace all elements in the referenced array with the given value. */ - void fill(const T &value) + constexpr void fill(const T &value) { initialized_fill_n(data_, size_, value); } @@ -489,7 +492,7 @@ template<typename T> class MutableSpan { * Replace a subset of all elements with the given value. This invokes undefined behavior when * one of the indices is out of bounds. */ - void fill_indices(Span<int64_t> indices, const T &value) + constexpr void fill_indices(Span<int64_t> indices, const T &value) { for (int64_t i : indices) { BLI_assert(i < size_); @@ -501,30 +504,30 @@ template<typename T> class MutableSpan { * Returns a pointer to the beginning of the referenced array. This may be nullptr, when the size * is zero. */ - T *data() const + constexpr T *data() const { return data_; } - T *begin() const + constexpr T *begin() const { return data_; } - T *end() const + constexpr T *end() const { return data_ + size_; } - std::reverse_iterator<T *> rbegin() const + constexpr std::reverse_iterator<T *> rbegin() const { return std::reverse_iterator<T *>(this->end()); } - std::reverse_iterator<T *> rend() const + constexpr std::reverse_iterator<T *> rend() const { return std::reverse_iterator<T *>(this->begin()); } - T &operator[](const int64_t index) const + constexpr T &operator[](const int64_t index) const { BLI_assert(index < this->size()); return data_[index]; @@ -534,7 +537,7 @@ template<typename T> class MutableSpan { * Returns a contiguous part of the array. This invokes undefined behavior when the slice would * go out of bounds. */ - MutableSpan slice(const int64_t start, const int64_t length) const + constexpr MutableSpan slice(const int64_t start, const int64_t length) const { BLI_assert(start + length <= this->size()); return MutableSpan(data_ + start, length); @@ -544,7 +547,7 @@ template<typename T> class MutableSpan { * Returns a new MutableSpan with n elements removed from the beginning. This invokes * undefined behavior when the array is too small. */ - MutableSpan drop_front(const int64_t n) const + constexpr MutableSpan drop_front(const int64_t n) const { BLI_assert(n <= this->size()); return this->slice(n, this->size() - n); @@ -554,7 +557,7 @@ template<typename T> class MutableSpan { * Returns a new MutableSpan with n elements removed from the end. This invokes undefined * behavior when the array is too small. */ - MutableSpan drop_back(const int64_t n) const + constexpr MutableSpan drop_back(const int64_t n) const { BLI_assert(n <= this->size()); return this->slice(0, this->size() - n); @@ -564,7 +567,7 @@ template<typename T> class MutableSpan { * Returns a new MutableSpan that only contains the first n elements. This invokes undefined * behavior when the array is too small. */ - MutableSpan take_front(const int64_t n) const + constexpr MutableSpan take_front(const int64_t n) const { BLI_assert(n <= this->size()); return this->slice(0, n); @@ -574,7 +577,7 @@ template<typename T> class MutableSpan { * Return a new MutableSpan that only contains the last n elements. This invokes undefined * behavior when the array is too small. */ - MutableSpan take_back(const int64_t n) const + constexpr MutableSpan take_back(const int64_t n) const { BLI_assert(n <= this->size()); return this->slice(this->size() - n, n); @@ -584,7 +587,7 @@ template<typename T> class MutableSpan { * Returns an (immutable) Span that references the same array. This is usually not needed, * due to implicit conversions. However, sometimes automatic type deduction needs some help. */ - Span<T> as_span() const + constexpr Span<T> as_span() const { return Span<T>(data_, size_); } @@ -593,7 +596,7 @@ template<typename T> class MutableSpan { * Utility to make it more convenient to iterate over all indices that can be used with this * array. */ - IndexRange index_range() const + constexpr IndexRange index_range() const { return IndexRange(size_); } @@ -602,7 +605,7 @@ template<typename T> class MutableSpan { * Returns a reference to the last element. This invokes undefined behavior when the array is * empty. */ - T &last() const + constexpr T &last() const { BLI_assert(size_ > 0); return data_[size_ - 1]; @@ -612,7 +615,7 @@ template<typename T> class MutableSpan { * Does a linear search to count how often the value is in the array. * Returns the number of occurrences. */ - int64_t count(const T &value) const + constexpr int64_t count(const T &value) const { int64_t counter = 0; for (const T &element : *this) { @@ -628,7 +631,7 @@ template<typename T> class MutableSpan { * destination contains uninitialized data and T is not trivially copy constructible. * The size of both spans is expected to be the same. */ - void copy_from(Span<T> values) + constexpr void copy_from(Span<T> values) { BLI_assert(size_ == values.size()); initialized_copy_n(values.data(), size_, data_); @@ -637,7 +640,7 @@ template<typename T> class MutableSpan { /** * Returns a new span to the same underlying memory buffer. No conversions are done. */ - template<typename NewT> MutableSpan<NewT> cast() const + template<typename NewT> constexpr MutableSpan<NewT> cast() const { BLI_assert((size_ * sizeof(T)) % sizeof(NewT) == 0); int64_t new_size = size_ * sizeof(T) / sizeof(NewT); @@ -648,7 +651,7 @@ template<typename T> class MutableSpan { /** * Utilities to check that arrays have the same size in debug builds. */ -template<typename T1, typename T2> void assert_same_size(const T1 &v1, const T2 &v2) +template<typename T1, typename T2> constexpr void assert_same_size(const T1 &v1, const T2 &v2) { UNUSED_VARS_NDEBUG(v1, v2); #ifdef DEBUG @@ -659,7 +662,7 @@ template<typename T1, typename T2> void assert_same_size(const T1 &v1, const T2 } template<typename T1, typename T2, typename T3> -void assert_same_size(const T1 &v1, const T2 &v2, const T3 &v3) +constexpr void assert_same_size(const T1 &v1, const T2 &v2, const T3 &v3) { UNUSED_VARS_NDEBUG(v1, v2, v3); #ifdef DEBUG diff --git a/source/blender/blenlib/BLI_string.h b/source/blender/blenlib/BLI_string.h index 2d745e63764..096e7818013 100644 --- a/source/blender/blenlib/BLI_string.h +++ b/source/blender/blenlib/BLI_string.h @@ -85,8 +85,11 @@ size_t BLI_vsnprintf_rlen(char *__restrict buffer, char *BLI_sprintfN(const char *__restrict format, ...) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_PRINTF_FORMAT(1, 2); -size_t BLI_strescape(char *__restrict dst, const char *__restrict src, const size_t maxncpy) +size_t BLI_str_escape(char *__restrict dst, const char *__restrict src, const size_t dst_maxncpy) ATTR_NONNULL(); +size_t BLI_str_unescape(char *__restrict dst, const char *__restrict src, const size_t src_maxncpy) + ATTR_NONNULL(); +const char *BLI_str_escape_find_quote(const char *str) ATTR_NONNULL(); size_t BLI_str_format_int_grouped(char dst[16], int num) ATTR_NONNULL(); size_t BLI_str_format_uint64_grouped(char dst[16], uint64_t num) ATTR_NONNULL(); diff --git a/source/blender/blenlib/BLI_string_ref.hh b/source/blender/blenlib/BLI_string_ref.hh index 8597e54d03b..a2562c6100a 100644 --- a/source/blender/blenlib/BLI_string_ref.hh +++ b/source/blender/blenlib/BLI_string_ref.hh @@ -64,7 +64,7 @@ class StringRefBase { const char *data_; int64_t size_; - StringRefBase(const char *data, const int64_t size) : data_(data), size_(size) + constexpr StringRefBase(const char *data, const int64_t size) : data_(data), size_(size) { } @@ -75,12 +75,12 @@ class StringRefBase { /** * Return the (byte-)length of the referenced string, without any null-terminator. */ - int64_t size() const + constexpr int64_t size() const { return size_; } - bool is_empty() const + constexpr bool is_empty() const { return size_ == 0; } @@ -88,12 +88,12 @@ class StringRefBase { /** * Return a pointer to the start of the string. */ - const char *data() const + constexpr const char *data() const { return data_; } - operator Span<char>() const + constexpr operator Span<char>() const { return Span<char>(data_, size_); } @@ -107,22 +107,22 @@ class StringRefBase { return std::string(data_, static_cast<size_t>(size_)); } - operator std::string_view() const + constexpr operator std::string_view() const { return std::string_view(data_, static_cast<size_t>(size_)); } - const char *begin() const + constexpr const char *begin() const { return data_; } - const char *end() const + constexpr const char *end() const { return data_ + size_; } - IndexRange index_range() const + constexpr IndexRange index_range() const { return IndexRange(size_); } @@ -165,19 +165,19 @@ class StringRefBase { /** * Returns true when the string begins with the given prefix. Otherwise false. */ - bool startswith(StringRef prefix) const; + constexpr bool startswith(StringRef prefix) const; /** * Returns true when the string ends with the given suffix. Otherwise false. */ - bool endswith(StringRef suffix) const; + constexpr bool endswith(StringRef suffix) const; - StringRef substr(int64_t start, const int64_t size) const; + constexpr StringRef substr(int64_t start, const int64_t size) const; /** * Get the first char in the string. This invokes undefined behavior when the string is empty. */ - const char &front() const + constexpr const char &front() const { BLI_assert(size_ >= 1); return data_[0]; @@ -186,7 +186,7 @@ class StringRefBase { /** * Get the last char in the string. This invokes undefined behavior when the string is empty. */ - const char &back() const + constexpr const char &back() const { BLI_assert(size_ >= 1); return data_[size_ - 1]; @@ -196,18 +196,18 @@ class StringRefBase { * The behavior of those functions matches the standard library implementation of * std::string_view. */ - int64_t find(char c, int64_t pos = 0) const; - int64_t find(StringRef str, int64_t pos = 0) const; - int64_t rfind(char c, int64_t pos = INT64_MAX) const; - int64_t rfind(StringRef str, int64_t pos = INT64_MAX) const; - int64_t find_first_of(StringRef chars, int64_t pos = 0) const; - int64_t find_first_of(char c, int64_t pos = 0) const; - int64_t find_last_of(StringRef chars, int64_t pos = INT64_MAX) const; - int64_t find_last_of(char c, int64_t pos = INT64_MAX) const; - int64_t find_first_not_of(StringRef chars, int64_t pos = 0) const; - int64_t find_first_not_of(char c, int64_t pos = 0) const; - int64_t find_last_not_of(StringRef chars, int64_t pos = INT64_MAX) const; - int64_t find_last_not_of(char c, int64_t pos = INT64_MAX) const; + constexpr int64_t find(char c, int64_t pos = 0) const; + constexpr int64_t find(StringRef str, int64_t pos = 0) const; + constexpr int64_t rfind(char c, int64_t pos = INT64_MAX) const; + constexpr int64_t rfind(StringRef str, int64_t pos = INT64_MAX) const; + constexpr int64_t find_first_of(StringRef chars, int64_t pos = 0) const; + constexpr int64_t find_first_of(char c, int64_t pos = 0) const; + constexpr int64_t find_last_of(StringRef chars, int64_t pos = INT64_MAX) const; + constexpr int64_t find_last_of(char c, int64_t pos = INT64_MAX) const; + constexpr int64_t find_first_not_of(StringRef chars, int64_t pos = 0) const; + constexpr int64_t find_first_not_of(char c, int64_t pos = 0) const; + constexpr int64_t find_last_not_of(StringRef chars, int64_t pos = INT64_MAX) const; + constexpr int64_t find_last_not_of(char c, int64_t pos = INT64_MAX) const; }; /** @@ -216,7 +216,7 @@ class StringRefBase { class StringRefNull : public StringRefBase { public: - StringRefNull() : StringRefBase("", 0) + constexpr StringRefNull() : StringRefBase("", 0) { } @@ -226,7 +226,7 @@ class StringRefNull : public StringRefBase { */ StringRefNull(const char *str) : StringRefBase(str, static_cast<int64_t>(strlen(str))) { - BLI_assert(str != NULL); + BLI_assert(str != nullptr); BLI_assert(data_[size_] == '\0'); } @@ -234,7 +234,7 @@ class StringRefNull : public StringRefBase { * Construct a StringRefNull from a null terminated c-string. This invokes undefined behavior * when the given size is not the correct size of the string. */ - StringRefNull(const char *str, const int64_t size) : StringRefBase(str, size) + constexpr StringRefNull(const char *str, const int64_t size) : StringRefBase(str, size) { BLI_assert(static_cast<int64_t>(strlen(str)) == size); } @@ -250,7 +250,7 @@ class StringRefNull : public StringRefBase { /** * Get the char at the given index. */ - char operator[](const int64_t index) const + constexpr char operator[](const int64_t index) const { BLI_assert(index >= 0); /* Use '<=' instead of just '<', so that the null character can be accessed as well. */ @@ -263,7 +263,7 @@ class StringRefNull : public StringRefBase { * * This is like ->data(), but can only be called on a StringRefNull. */ - const char *c_str() const + constexpr const char *c_str() const { return data_; } @@ -274,25 +274,26 @@ class StringRefNull : public StringRefBase { */ class StringRef : public StringRefBase { public: - StringRef() : StringRefBase(nullptr, 0) + constexpr StringRef() : StringRefBase(nullptr, 0) { } /** * StringRefNull can be converted into StringRef, but not the other way around. */ - StringRef(StringRefNull other) : StringRefBase(other.data(), other.size()) + constexpr StringRef(StringRefNull other) : StringRefBase(other.data(), other.size()) { } /** * Create a StringRef from a null-terminated c-string. */ - StringRef(const char *str) : StringRefBase(str, str ? static_cast<int64_t>(strlen(str)) : 0) + constexpr StringRef(const char *str) + : StringRefBase(str, str ? static_cast<int64_t>(std::char_traits<char>::length(str)) : 0) { } - StringRef(const char *str, const int64_t length) : StringRefBase(str, length) + constexpr StringRef(const char *str, const int64_t length) : StringRefBase(str, length) { } @@ -300,7 +301,7 @@ class StringRef : public StringRefBase { * Create a StringRef from a start and end pointer. This invokes undefined behavior when the * second point points to a smaller address than the first one. */ - StringRef(const char *begin, const char *one_after_end) + constexpr StringRef(const char *begin, const char *one_after_end) : StringRefBase(begin, static_cast<int64_t>(one_after_end - begin)) { BLI_assert(begin <= one_after_end); @@ -314,7 +315,8 @@ class StringRef : public StringRefBase { { } - StringRef(std::string_view view) : StringRefBase(view.data(), static_cast<int64_t>(view.size())) + constexpr StringRef(std::string_view view) + : StringRefBase(view.data(), static_cast<int64_t>(view.size())) { } @@ -323,7 +325,7 @@ class StringRef : public StringRefBase { * * This is similar to std::string_view::remove_prefix. */ - StringRef drop_prefix(const int64_t n) const + constexpr StringRef drop_prefix(const int64_t n) const { BLI_assert(n >= 0); BLI_assert(n <= size_); @@ -334,7 +336,7 @@ class StringRef : public StringRefBase { * Return a new StringRef with the given prefix being skipped. This invokes undefined behavior if * the string does not begin with the given prefix. */ - StringRef drop_prefix(StringRef prefix) const + constexpr StringRef drop_prefix(StringRef prefix) const { BLI_assert(this->startswith(prefix)); return this->drop_prefix(prefix.size()); @@ -345,7 +347,7 @@ class StringRef : public StringRefBase { * * This is similar to std::string_view::remove_suffix. */ - StringRef drop_suffix(const int64_t n) const + constexpr StringRef drop_suffix(const int64_t n) const { BLI_assert(n >= 0); BLI_assert(n <= size_); @@ -355,7 +357,7 @@ class StringRef : public StringRefBase { /** * Get the char at the given index. */ - char operator[](int64_t index) const + constexpr char operator[](int64_t index) const { BLI_assert(index >= 0); BLI_assert(index < size_); @@ -391,7 +393,7 @@ inline std::string operator+(StringRef a, StringRef b) * not a problem when std::string_view is only used at api boundaries. To compare a StringRef and a * std::string_view, one should convert the std::string_view to StringRef (which is very cheap). * Ideally, we only use StringRef in our code to avoid this problem altogether. */ -inline bool operator==(StringRef a, StringRef b) +constexpr inline bool operator==(StringRef a, StringRef b) { if (a.size() != b.size()) { return false; @@ -399,27 +401,27 @@ inline bool operator==(StringRef a, StringRef b) return STREQLEN(a.data(), b.data(), (size_t)a.size()); } -inline bool operator!=(StringRef a, StringRef b) +constexpr inline bool operator!=(StringRef a, StringRef b) { return !(a == b); } -inline bool operator<(StringRef a, StringRef b) +constexpr inline bool operator<(StringRef a, StringRef b) { return std::string_view(a) < std::string_view(b); } -inline bool operator>(StringRef a, StringRef b) +constexpr inline bool operator>(StringRef a, StringRef b) { return std::string_view(a) > std::string_view(b); } -inline bool operator<=(StringRef a, StringRef b) +constexpr inline bool operator<=(StringRef a, StringRef b) { return std::string_view(a) <= std::string_view(b); } -inline bool operator>=(StringRef a, StringRef b) +constexpr inline bool operator>=(StringRef a, StringRef b) { return std::string_view(a) >= std::string_view(b); } @@ -427,7 +429,7 @@ inline bool operator>=(StringRef a, StringRef b) /** * Return true when the string starts with the given prefix. */ -inline bool StringRefBase::startswith(StringRef prefix) const +constexpr inline bool StringRefBase::startswith(StringRef prefix) const { if (size_ < prefix.size_) { return false; @@ -443,7 +445,7 @@ inline bool StringRefBase::startswith(StringRef prefix) const /** * Return true when the string ends with the given suffix. */ -inline bool StringRefBase::endswith(StringRef suffix) const +constexpr inline bool StringRefBase::endswith(StringRef suffix) const { if (size_ < suffix.size_) { return false; @@ -460,8 +462,8 @@ inline bool StringRefBase::endswith(StringRef suffix) const /** * Return a new #StringRef containing only a sub-string of the original string. */ -inline StringRef StringRefBase::substr(const int64_t start, - const int64_t max_size = INT64_MAX) const +constexpr inline StringRef StringRefBase::substr(const int64_t start, + const int64_t max_size = INT64_MAX) const { BLI_assert(max_size >= 0); BLI_assert(start >= 0); @@ -469,7 +471,7 @@ inline StringRef StringRefBase::substr(const int64_t start, return StringRef(data_ + start, substr_size); } -inline int64_t index_or_npos_to_int64(size_t index) +constexpr inline int64_t index_or_npos_to_int64(size_t index) { /* The compiler will probably optimize this check away. */ if (index == std::string_view::npos) { @@ -478,62 +480,62 @@ inline int64_t index_or_npos_to_int64(size_t index) return static_cast<int64_t>(index); } -inline int64_t StringRefBase::find(char c, int64_t pos) const +constexpr inline int64_t StringRefBase::find(char c, int64_t pos) const { BLI_assert(pos >= 0); return index_or_npos_to_int64(std::string_view(*this).find(c, static_cast<size_t>(pos))); } -inline int64_t StringRefBase::find(StringRef str, int64_t pos) const +constexpr inline int64_t StringRefBase::find(StringRef str, int64_t pos) const { BLI_assert(pos >= 0); return index_or_npos_to_int64(std::string_view(*this).find(str, static_cast<size_t>(pos))); } -inline int64_t StringRefBase::find_first_of(StringRef chars, int64_t pos) const +constexpr inline int64_t StringRefBase::find_first_of(StringRef chars, int64_t pos) const { BLI_assert(pos >= 0); return index_or_npos_to_int64( std::string_view(*this).find_first_of(chars, static_cast<size_t>(pos))); } -inline int64_t StringRefBase::find_first_of(char c, int64_t pos) const +constexpr inline int64_t StringRefBase::find_first_of(char c, int64_t pos) const { return this->find_first_of(StringRef(&c, 1), pos); } -inline int64_t StringRefBase::find_last_of(StringRef chars, int64_t pos) const +constexpr inline int64_t StringRefBase::find_last_of(StringRef chars, int64_t pos) const { BLI_assert(pos >= 0); return index_or_npos_to_int64( std::string_view(*this).find_last_of(chars, static_cast<size_t>(pos))); } -inline int64_t StringRefBase::find_last_of(char c, int64_t pos) const +constexpr inline int64_t StringRefBase::find_last_of(char c, int64_t pos) const { return this->find_last_of(StringRef(&c, 1), pos); } -inline int64_t StringRefBase::find_first_not_of(StringRef chars, int64_t pos) const +constexpr inline int64_t StringRefBase::find_first_not_of(StringRef chars, int64_t pos) const { BLI_assert(pos >= 0); return index_or_npos_to_int64( std::string_view(*this).find_first_not_of(chars, static_cast<size_t>(pos))); } -inline int64_t StringRefBase::find_first_not_of(char c, int64_t pos) const +constexpr inline int64_t StringRefBase::find_first_not_of(char c, int64_t pos) const { return this->find_first_not_of(StringRef(&c, 1), pos); } -inline int64_t StringRefBase::find_last_not_of(StringRef chars, int64_t pos) const +constexpr inline int64_t StringRefBase::find_last_not_of(StringRef chars, int64_t pos) const { BLI_assert(pos >= 0); return index_or_npos_to_int64( std::string_view(*this).find_last_not_of(chars, static_cast<size_t>(pos))); } -inline int64_t StringRefBase::find_last_not_of(char c, int64_t pos) const +constexpr inline int64_t StringRefBase::find_last_not_of(char c, int64_t pos) const { return this->find_last_not_of(StringRef(&c, 1), pos); } diff --git a/source/blender/blenlib/BLI_threads.h b/source/blender/blenlib/BLI_threads.h index d19b5393aa7..eefde1afefb 100644 --- a/source/blender/blenlib/BLI_threads.h +++ b/source/blender/blenlib/BLI_threads.h @@ -35,7 +35,6 @@ extern "C" { #define BLENDER_MAX_THREADS 1024 struct ListBase; -struct TaskScheduler; /* Threading API */ diff --git a/source/blender/blenlib/BLI_vector.hh b/source/blender/blenlib/BLI_vector.hh index 053dcb6faea..fe6d54ae9e5 100644 --- a/source/blender/blenlib/BLI_vector.hh +++ b/source/blender/blenlib/BLI_vector.hh @@ -315,13 +315,13 @@ class Vector { return MutableSpan<T>(begin_, this->size()); } - template<typename U, typename std::enable_if_t<is_convertible_pointer_v<T, U>> * = nullptr> + template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<T, U>> * = nullptr> operator Span<U>() const { return Span<U>(begin_, this->size()); } - template<typename U, typename std::enable_if_t<is_convertible_pointer_v<T, U>> * = nullptr> + template<typename U, typename std::enable_if_t<is_span_convertible_pointer_v<T, U>> * = nullptr> operator MutableSpan<U>() { return MutableSpan<U>(begin_, this->size()); diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index 46a3ad87dfe..aa4c4efe7d4 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -203,6 +203,7 @@ set(SRC BLI_heap_simple.h BLI_index_mask.hh BLI_index_range.hh + BLI_inplace_priority_queue.hh BLI_iterator.h BLI_jitter_2d.h BLI_kdopbvh.h @@ -390,6 +391,7 @@ if(WITH_GTESTS) tests/BLI_heap_test.cc tests/BLI_index_mask_test.cc tests/BLI_index_range_test.cc + tests/BLI_inplace_priority_queue_test.cc tests/BLI_kdopbvh_test.cc tests/BLI_linear_allocator_test.cc tests/BLI_linklist_lockfree_test.cc diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c index f126c5a977b..0f90ad3a490 100644 --- a/source/blender/blenlib/intern/BLI_kdopbvh.c +++ b/source/blender/blenlib/intern/BLI_kdopbvh.c @@ -1076,6 +1076,25 @@ float BLI_bvhtree_get_epsilon(const BVHTree *tree) return tree->epsilon; } +/** + * This function returns the bounding box of the BVH tree. + */ +void BLI_bvhtree_get_bounding_box(BVHTree *tree, float r_bb_min[3], float r_bb_max[3]) +{ + BVHNode *root = tree->nodes[tree->totleaf]; + if (root != NULL) { + const float bb_min[3] = {root->bv[0], root->bv[2], root->bv[4]}; + const float bb_max[3] = {root->bv[1], root->bv[3], root->bv[5]}; + copy_v3_v3(r_bb_min, bb_min); + copy_v3_v3(r_bb_max, bb_max); + } + else { + BLI_assert(false); + zero_v3(r_bb_min); + zero_v3(r_bb_max); + } +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c index a0ee16bee76..19828e69638 100644 --- a/source/blender/blenlib/intern/math_rotation.c +++ b/source/blender/blenlib/intern/math_rotation.c @@ -372,6 +372,11 @@ void mat3_normalized_to_quat(float q[4], const float mat[3][3]) q[1] = (mat[2][0] + mat[0][2]) * s; q[2] = (mat[2][1] + mat[1][2]) * s; } + + /* Make sure w is nonnegative for a canonical result. */ + if (q[0] < 0) { + negate_v4(q); + } } normalize_qt(q); @@ -556,10 +561,20 @@ void rotation_between_quats_to_quat(float q[4], const float q1[4], const float q * \param r_twist: if not NULL, receives the twist quaternion. * \returns twist angle. */ -float quat_split_swing_and_twist(const float q[4], int axis, float r_swing[4], float r_twist[4]) +float quat_split_swing_and_twist(const float q_in[4], int axis, float r_swing[4], float r_twist[4]) { BLI_assert(axis >= 0 && axis <= 2); + /* The calculation requires a canonical quaternion. */ + float q[4]; + + if (q_in[0] < 0) { + negate_v4_v4(q, q_in); + } + else { + copy_v4_v4(q, q_in); + } + /* Half-twist angle can be computed directly. */ float t = atan2f(q[axis + 1], q[0]); diff --git a/source/blender/blenlib/intern/mesh_boolean.cc b/source/blender/blenlib/intern/mesh_boolean.cc index 2db939cd628..88d90a7816f 100644 --- a/source/blender/blenlib/intern/mesh_boolean.cc +++ b/source/blender/blenlib/intern/mesh_boolean.cc @@ -401,11 +401,6 @@ class Cell { void add_patch(int p) { - patches_.add_new(p); - } - - void add_patch_non_duplicates(int p) - { patches_.add(p); } @@ -693,7 +688,7 @@ static void merge_cells(int merge_to, int merge_from, CellsInfo &cinfo, PatchesI merge_to_cell = cinfo.cell(final_merge_to); } for (int cell_p : merge_from_cell.patches()) { - merge_to_cell.add_patch_non_duplicates(cell_p); + merge_to_cell.add_patch(cell_p); Patch &patch = pinfo.patch(cell_p); if (patch.cell_above == merge_from) { patch.cell_above = merge_to; diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index 758feef6093..5636ffafb6a 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -32,6 +32,7 @@ #include "BLI_fnmatch.h" #include "BLI_path_util.h" #include "BLI_string.h" +#include "BLI_string_utf8.h" #include "BLI_utildefines.h" #ifdef WIN32 @@ -264,6 +265,11 @@ void BLI_path_normalize(const char *relabase, char *path) */ void BLI_path_normalize_dir(const char *relabase, char *dir) { + /* Would just create an unexpected "/" path, just early exit entirely. */ + if (dir[0] == '\0') { + return; + } + BLI_path_normalize(relabase, dir); BLI_path_slash_ensure(dir); } @@ -282,7 +288,7 @@ void BLI_path_normalize_dir(const char *relabase, char *dir) * (good practice anyway). * REMOVED based on popular demand (see T45900). * Percent '%' char is a bit same case - not recommended to use it, - * but supported by all decent FS/OS around. + * but supported by all decent file-systems/operating-systems around. * * \note On Windows, it also ensures there is no '.' (dot char) at the end of the file, * this can lead to issues. @@ -507,8 +513,8 @@ void BLI_path_normalize_unc_16(wchar_t *path_16) #endif /** - * Replaces *file with a relative version (prefixed by "//") such that BLI_path_abs, given - * the same *relfile, will convert it back to its original value. + * Replaces `file` with a relative version (prefixed by "//") such that #BLI_path_abs, given + * the same `relfile`, will convert it back to its original value. */ void BLI_path_rel(char *file, const char *relfile) { @@ -658,7 +664,7 @@ void BLI_path_rel(char *file, const char *relfile) * \param maxlen: Maximum length of string * \param suffix: String to append to the original string * \param sep: Optional separator character - * \return true if succeeded + * \return true if succeeded */ bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char *sep) { @@ -697,7 +703,7 @@ bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char /** * Replaces path with the path of its parent directory, returning true if - * it was able to find a parent directory within the pathname. + * it was able to find a parent directory within the path. */ bool BLI_path_parent_dir(char *path) { @@ -716,7 +722,7 @@ bool BLI_path_parent_dir(char *path) } /** - * Strips off nonexistent (or non-accessible) subdirectories from the end of *dir, + * Strips off nonexistent (or non-accessible) sub-directories from the end of `dir`, * leaving the path of the lowest-level directory that does exist and we can read. */ bool BLI_path_parent_dir_until_exists(char *dir) @@ -731,9 +737,9 @@ bool BLI_path_parent_dir_until_exists(char *dir) } /** - * Looks for a sequence of "#" characters in the last slash-separated component of *path, + * Looks for a sequence of "#" characters in the last slash-separated component of `path`, * returning the indexes of the first and one past the last character in the sequence in - * *char_start and *char_end respectively. Returns true if such a sequence was found. + * `char_start` and `char_end` respectively. Returns true if such a sequence was found. */ static bool stringframe_chars(const char *path, int *char_start, int *char_end) { @@ -768,7 +774,7 @@ static bool stringframe_chars(const char *path, int *char_start, int *char_end) } /** - * Ensure *path contains at least one "#" character in its last slash-separated + * Ensure `path` contains at least one "#" character in its last slash-separated * component, appending one digits long if not. */ static void ensure_digits(char *path, int digits) @@ -790,7 +796,7 @@ static void ensure_digits(char *path, int digits) } /** - * Replaces "#" character sequence in last slash-separated component of *path + * Replaces "#" character sequence in last slash-separated component of `path` * with frame as decimal integer, with leading zeroes as necessary, to make digits digits. */ bool BLI_path_frame(char *path, int frame, int digits) @@ -812,7 +818,7 @@ bool BLI_path_frame(char *path, int frame, int digits) } /** - * Replaces "#" character sequence in last slash-separated component of *path + * Replaces "#" character sequence in last slash-separated component of `path` * with sta and end as decimal integers, with leading zeroes as necessary, to make digits * digits each, with a hyphen in-between. */ @@ -957,7 +963,7 @@ bool BLI_path_frame_check_chars(const char *path) /** * Creates a display string from path to be used menus and the user interface. - * Like bpy.path.display_name(). + * Like `bpy.path.display_name()`. */ void BLI_path_to_display_name(char *display_name, int maxlen, const char *name) { @@ -998,7 +1004,7 @@ void BLI_path_to_display_name(char *display_name, int maxlen, const char *name) } /** - * If path begins with "//", strips that and replaces it with basepath directory. + * If path begins with "//", strips that and replaces it with `basepath` directory. * * \note Also converts drive-letter prefix to something more sensible * if this is a non-drive-letter-based system. @@ -1156,7 +1162,7 @@ bool BLI_path_abs_from_cwd(char *path, const size_t maxlen) #ifdef _WIN32 /** * Tries appending each of the semicolon-separated extensions in the PATHEXT - * environment variable (Windows-only) onto *name in turn until such a file is found. + * environment variable (Windows-only) onto `name` in turn until such a file is found. * Returns success/failure. */ bool BLI_path_program_extensions_add_win32(char *name, const size_t maxlen) @@ -1263,7 +1269,7 @@ bool BLI_path_program_search(char *fullname, const size_t maxlen, const char *na /** * Sets the specified environment variable to the specified value, - * and clears it if val == NULL. + * and clears it if `val == NULL`. */ void BLI_setenv(const char *env, const char *val) { @@ -1299,30 +1305,44 @@ void BLI_setenv_if_new(const char *env, const char *val) /** * Get an env var, result has to be used immediately. * - * On windows getenv gets its variables from a static copy of the environment variables taken at + * On windows #getenv gets its variables from a static copy of the environment variables taken at * process start-up, causing it to not pick up on environment variables created during runtime. * This function uses an alternative method to get environment variables that does pick up on - * runtime environment variables. + * runtime environment variables. The result will be UTF-8 encoded. */ const char *BLI_getenv(const char *env) { #ifdef _MSC_VER - static char buffer[32767]; /* 32767 is the total size of the environment block on windows*/ - if (GetEnvironmentVariableA(env, buffer, sizeof(buffer))) { - return buffer; - } - else { - return NULL; + const char *result = NULL; + /* 32767 is the maximum size of the environment variable on windows, + * reserve one more character for the zero terminator. */ + static wchar_t buffer[32768]; + wchar_t *env_16 = alloc_utf16_from_8(env, 0); + if (env_16) { + if (GetEnvironmentVariableW(env_16, buffer, ARRAY_SIZE(buffer))) { + char *res_utf8 = alloc_utf_8_from_16(buffer, 0); + /* Make sure the result is valid, and will fit into our temporary storage buffer. */ + if (res_utf8) { + if (strlen(res_utf8) + 1 < sizeof(buffer)) { + /* We are re-using the utf16 buffer here, since allocating a second static buffer to + * contain the UTF-8 version to return would be wasteful. */ + memcpy(buffer, res_utf8, strlen(res_utf8) + 1); + result = (const char *)buffer; + } + free(res_utf8); + } + } } + return result; #else return getenv(env); #endif } /** - * Ensures that the parent directory of *name exists. + * Ensures that the parent directory of `name` exists. * - * \return true on success (i.e. given path now exists on FS), false otherwise. + * \return true on success (i.e. given path now exists on file-system), false otherwise. */ bool BLI_make_existing_file(const char *name) { @@ -1334,13 +1354,13 @@ bool BLI_make_existing_file(const char *name) } /** - * 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. + * 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 + * \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) { @@ -1480,9 +1500,8 @@ bool BLI_path_extension_check_array(const char *str, const char **ext_array) } /** - * Semicolon separated wildcards, eg: - * '*.zip;*.py;*.exe' - * does str match any of the semicolon-separated glob patterns in fnmatch. + * Semicolon separated wildcards, eg: `*.zip;*.py;*.exe` + * does str match any of the semicolon-separated glob patterns in #fnmatch. */ bool BLI_path_extension_check_glob(const char *str, const char *ext_fnmatch) { @@ -1511,10 +1530,11 @@ bool BLI_path_extension_check_glob(const char *str, const char *ext_fnmatch) } /** - * Does basic validation of the given glob string, to prevent common issues from string truncation. + * Does basic validation of the given glob string, to prevent common issues from string + * truncation. * * For now, only forbids last group to be a wildcard-only one, if there are more than one group - * (i.e. things like "*.txt;*.cpp;*" are changed to "*.txt;*.cpp;") + * (i.e. things like `*.txt;*.cpp;*` are changed to `*.txt;*.cpp;`) * * \returns true if it had to modify given \a ext_fnmatch pattern. */ @@ -1624,7 +1644,7 @@ bool BLI_path_filename_ensure(char *filepath, size_t maxlen, const char *filenam } /** - * Converts `/foo/bar.txt` to "/foo/" and `bar.txt` + * Converts `/foo/bar.txt` to `/foo/` and `bar.txt` * * - Wont change \a string. * - Wont create any directories. @@ -1657,7 +1677,7 @@ void BLI_split_dirfile( } /** - * Copies the parent directory part of string into *dir, max length dirlen. + * Copies the parent directory part of string into `dir`, max length `dirlen`. */ void BLI_split_dir_part(const char *string, char *dir, const size_t dirlen) { @@ -1665,7 +1685,7 @@ void BLI_split_dir_part(const char *string, char *dir, const size_t dirlen) } /** - * Copies the leaf filename part of string into *file, max length filelen. + * Copies the leaf filename part of string into `file`, max length `filelen`. */ void BLI_split_file_part(const char *string, char *file, const size_t filelen) { @@ -1712,7 +1732,7 @@ void BLI_path_append(char *__restrict dst, const size_t maxlen, const char *__re /** * Simple appending of filename to dir, does not check for valid path! - * Puts result into *dst, which may be same area as *dir. + * Puts result into `dst`, which may be same area as `dir`. */ void BLI_join_dirfile(char *__restrict dst, const size_t maxlen, @@ -1756,7 +1776,7 @@ void BLI_join_dirfile(char *__restrict dst, * Join multiple strings into a path, ensuring only a single path separator between each, * and trailing slash is kept. * - * \note If you want a trailing slash, add ``SEP_STR`` as the last path argument, + * \note If you want a trailing slash, add `SEP_STR` as the last path argument, * duplicate slashes will be cleaned up. */ size_t BLI_path_join(char *__restrict dst, const size_t dst_len, const char *path, ...) @@ -1840,7 +1860,7 @@ size_t BLI_path_join(char *__restrict dst, const size_t dst_len, const char *pat } /** - * like pythons os.path.basename() + * like Python's `os.path.basename()` * * \return The pointer into \a path string immediately after last slash, * or start of \a path if none found. diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c index 02d12d2df9b..b0d87838d06 100644 --- a/source/blender/blenlib/intern/string.c +++ b/source/blender/blenlib/intern/string.c @@ -317,92 +317,135 @@ char *BLI_sprintfN(const char *__restrict format, ...) return n; } -/* match pythons string escaping, assume double quotes - (") - * TODO: should be used to create RNA animation paths. - * TODO: support more fancy string escaping. current code is primitive - * this basically is an ascii version of PyUnicode_EncodeUnicodeEscape() - * which is a useful reference. */ -size_t BLI_strescape(char *__restrict dst, const char *__restrict src, const size_t maxncpy) +/** + * This roughly matches C and Python's string escaping with double quotes - `"`. + * + * Since every character may need escaping, + * it's common to create a buffer twice as large as the input. + * + * \param dst: The destination string, at least \a dst_maxncpy, typically `(strlen(src) * 2) + 1`. + * \param src: The un-escaped source string. + * \param dst_maxncpy: The maximum number of bytes allowable to copy. + * + * \note This is used for creating animation paths in blend files. + */ +size_t BLI_str_escape(char *__restrict dst, const char *__restrict src, const size_t dst_maxncpy) { - size_t len = 0; - BLI_assert(maxncpy != 0); + BLI_assert(dst_maxncpy != 0); - while (len < maxncpy) { - switch (*src) { - case '\0': - goto escape_finish; - case '\\': - case '"': - ATTR_FALLTHROUGH; - - /* less common but should also be support */ - case '\t': - case '\n': - case '\r': - if (len + 1 < maxncpy) { - *dst++ = '\\'; - len++; - } - else { - /* not enough space to escape */ - break; - } - ATTR_FALLTHROUGH; - default: - *dst = *src; + size_t len = 0; + for (; (len < dst_maxncpy) && (*src != '\0'); dst++, src++, len++) { + char c = *src; + if (ELEM(c, '\\', '"') || /* Use as-is. */ + ((c == '\t') && ((void)(c = 't'), true)) || /* Tab. */ + ((c == '\n') && ((void)(c = 'n'), true)) || /* Newline. */ + ((c == '\r') && ((void)(c = 'r'), true)) || /* Carriage return. */ + ((c == '\a') && ((void)(c = 'a'), true)) || /* Bell. */ + ((c == '\b') && ((void)(c = 'b'), true)) || /* Backspace. */ + ((c == '\f') && ((void)(c = 'f'), true))) /* Form-feed. */ + { + if (UNLIKELY(len + 1 >= dst_maxncpy)) { + /* Not enough space to escape. */ break; + } + *dst++ = '\\'; + len++; } - dst++; - src++; - len++; + *dst = c; } - -escape_finish: - *dst = '\0'; return len; } /** - * Makes a copy of the text within the "" that appear after some text 'blahblah' - * i.e. for string 'pose["apples"]' with prefix 'pose[', it should grab "apples" + * This roughly matches C and Python's string escaping with double quotes - `"`. + * + * The destination will never be larger than the source, it will either be the same + * or up to half when all characters are escaped. + * + * \param dst: The destination string, at least the size of `strlen(src) + 1`. + * \param src: The escaped source string. + * \param dst_maxncpy: The maximum number of bytes allowable to copy. * - * - str: is the entire string to chop - * - prefix: is the part of the string to leave out + * \note This is used for for parsing animation paths in blend files. + */ +size_t BLI_str_unescape(char *__restrict dst, const char *__restrict src, const size_t src_maxncpy) +{ + size_t len = 0; + for (size_t i = 0; i < src_maxncpy && (*src != '\0'); i++, src++) { + char c = *src; + if (c == '\\') { + char c_next = *(src + 1); + if (((c_next == '"') && ((void)(c = '"'), true)) || /* Quote. */ + ((c_next == '\\') && ((void)(c = '\\'), true)) || /* Backslash. */ + ((c_next == 't') && ((void)(c = '\t'), true)) || /* Tab. */ + ((c_next == 'n') && ((void)(c = '\n'), true)) || /* Newline. */ + ((c_next == 'r') && ((void)(c = '\r'), true)) || /* Carriage return. */ + ((c_next == 'a') && ((void)(c = '\a'), true)) || /* Bell. */ + ((c_next == 'b') && ((void)(c = '\b'), true)) || /* Backspace. */ + ((c_next == 'f') && ((void)(c = '\f'), true))) /* Form-feed. */ + { + i++; + src++; + } + } + + dst[len++] = c; + } + dst[len] = 0; + return len; +} + +/** + * Find the first un-escaped quote in the string (to find the end of the string). + */ +const char *BLI_str_escape_find_quote(const char *str) +{ + bool escape = false; + while (*str && (*str != '"' || escape)) { + /* A pair of back-slashes represents a single back-slash, + * only use a single back-slash for escaping. */ + escape = (escape == false) && (*str == '\\'); + str++; + } + return (*str == '"') ? str : NULL; +} + +/** + * Makes a copy of the text within the "" that appear after some text `blahblah`. + * i.e. for string `pose["apples"]` with prefix `pose[`, it will return `apples`. * - * Assume that the strings returned must be freed afterwards, and that the inputs will contain - * data we want... + * \param str: is the entire string to chop. + * \param prefix: is the part of the string to step over. * - * \return the offset and a length so as to avoid doing an allocation. + * Assume that the strings returned must be freed afterwards, + * and that the inputs will contain data we want. */ char *BLI_str_quoted_substrN(const char *__restrict str, const char *__restrict prefix) { - const char *startMatch, *endMatch; + const char *start_match, *end_match; - /* get the starting point (i.e. where prefix starts, and add prefixLen+1 + /* get the starting point (i.e. where prefix starts, and add prefix_len+1 * to it to get be after the first " */ - startMatch = strstr(str, prefix); - if (startMatch) { - const size_t prefixLen = strlen(prefix); - startMatch += prefixLen + 1; + start_match = strstr(str, prefix); + if (start_match) { + const size_t prefix_len = strlen(prefix); + start_match += prefix_len + 1; /* get the end point (i.e. where the next occurrence of " is after the starting point) */ - - endMatch = startMatch; - while ((endMatch = strchr(endMatch, '"'))) { - if (LIKELY(*(endMatch - 1) != '\\')) { - break; + end_match = BLI_str_escape_find_quote(start_match); + if (end_match) { + const size_t unescaped_len = (size_t)(end_match - start_match); + char *result = MEM_mallocN(sizeof(char) * (unescaped_len + 1), __func__); + const size_t escaped_len = BLI_str_unescape(result, start_match, unescaped_len); + if (escaped_len != unescaped_len) { + result = MEM_reallocN(result, sizeof(char) * (escaped_len + 1)); } - endMatch++; - } - - if (endMatch) { - /* return the slice indicated */ - return BLI_strdupn(startMatch, (size_t)(endMatch - startMatch)); + return result; } } - return BLI_strdupn("", 0); + return NULL; } /** diff --git a/source/blender/blenlib/intern/task_pool.cc b/source/blender/blenlib/intern/task_pool.cc index ad9fc967185..fc1145eb627 100644 --- a/source/blender/blenlib/intern/task_pool.cc +++ b/source/blender/blenlib/intern/task_pool.cc @@ -150,13 +150,13 @@ class TBBTaskGroup : public tbb::task_group { /* Task Pool */ -typedef enum TaskPoolType { +enum TaskPoolType { TASK_POOL_TBB, TASK_POOL_TBB_SUSPENDED, TASK_POOL_NO_THREADS, TASK_POOL_BACKGROUND, TASK_POOL_BACKGROUND_SERIAL, -} TaskPoolType; +}; struct TaskPool { TaskPoolType type; diff --git a/source/blender/blenlib/tests/BLI_index_range_test.cc b/source/blender/blenlib/tests/BLI_index_range_test.cc index d472ded0f18..ddaa067f50e 100644 --- a/source/blender/blenlib/tests/BLI_index_range_test.cc +++ b/source/blender/blenlib/tests/BLI_index_range_test.cc @@ -140,4 +140,11 @@ TEST(index_range, AsSpan) EXPECT_EQ(span[3], 7); } +TEST(index_range, constexpr_) +{ + constexpr IndexRange range = IndexRange(1, 1); + std::array<int, range[0]> compiles = {1}; + BLI_STATIC_ASSERT(range.size() == 1, ""); + EXPECT_EQ(compiles[0], 1); +} } // namespace blender::tests diff --git a/source/blender/blenlib/tests/BLI_inplace_priority_queue_test.cc b/source/blender/blenlib/tests/BLI_inplace_priority_queue_test.cc new file mode 100644 index 00000000000..3adf12f36a7 --- /dev/null +++ b/source/blender/blenlib/tests/BLI_inplace_priority_queue_test.cc @@ -0,0 +1,113 @@ +/* Apache License, Version 2.0 */ + +#include "testing/testing.h" + +#include "BLI_inplace_priority_queue.hh" +#include "BLI_rand.hh" + +namespace blender::tests { + +TEST(inplace_priority_queue, BuildSmall) +{ + Array<int> values = {1, 5, 2, 8, 5, 6, 5, 4, 3, 6, 7, 3}; + InplacePriorityQueue<int> priority_queue{values}; + + EXPECT_EQ(priority_queue.peek(), 8); + EXPECT_EQ(priority_queue.pop(), 8); + EXPECT_EQ(priority_queue.peek(), 7); + EXPECT_EQ(priority_queue.pop(), 7); + EXPECT_EQ(priority_queue.pop(), 6); + EXPECT_EQ(priority_queue.pop(), 6); + EXPECT_EQ(priority_queue.pop(), 5); +} + +TEST(inplace_priority_queue, DecreasePriority) +{ + Array<int> values = {5, 2, 7, 4}; + InplacePriorityQueue<int> priority_queue(values); + + EXPECT_EQ(priority_queue.peek(), 7); + values[2] = 0; + EXPECT_EQ(priority_queue.peek(), 0); + priority_queue.priority_decreased(2); + EXPECT_EQ(priority_queue.peek(), 5); +} + +TEST(inplace_priority_queue, IncreasePriority) +{ + Array<int> values = {5, 2, 7, 4}; + InplacePriorityQueue<int> priority_queue(values); + + EXPECT_EQ(priority_queue.peek(), 7); + values[1] = 10; + EXPECT_EQ(priority_queue.peek(), 7); + priority_queue.priority_increased(1); + EXPECT_EQ(priority_queue.peek(), 10); +} + +TEST(inplace_priority_queue, PopAll) +{ + RandomNumberGenerator rng; + Vector<int> values; + const int amount = 1000; + for (int i = 0; i < amount; i++) { + values.append(rng.get_int32() % amount); + } + + InplacePriorityQueue<int> priority_queue(values); + + int last_value = amount; + while (!priority_queue.is_empty()) { + const int value = priority_queue.pop(); + EXPECT_LE(value, last_value); + last_value = value; + } +} + +TEST(inplace_priority_queue, ManyPriorityChanges) +{ + RandomNumberGenerator rng; + Vector<int> values; + const int amount = 1000; + for (int i = 0; i < amount; i++) { + values.append(rng.get_int32() % amount); + } + + InplacePriorityQueue<int> priority_queue(values); + + for (int i = 0; i < amount; i++) { + const int index = rng.get_int32() % amount; + const int new_priority = rng.get_int32() % amount; + values[index] = new_priority; + priority_queue.priority_changed(index); + } + + int last_value = amount; + while (!priority_queue.is_empty()) { + const int value = priority_queue.pop(); + EXPECT_LE(value, last_value); + last_value = value; + } +} + +TEST(inplace_priority_queue, IndicesAccess) +{ + Array<int> values = {4, 6, 2, 4, 8, 1, 10, 2, 5}; + InplacePriorityQueue<int> priority_queue(values); + + EXPECT_EQ(priority_queue.active_indices().size(), 9); + EXPECT_EQ(priority_queue.inactive_indices().size(), 0); + EXPECT_EQ(priority_queue.all_indices().size(), 9); + EXPECT_EQ(priority_queue.pop(), 10); + EXPECT_EQ(priority_queue.active_indices().size(), 8); + EXPECT_EQ(priority_queue.inactive_indices().size(), 1); + EXPECT_EQ(values[priority_queue.inactive_indices()[0]], 10); + EXPECT_EQ(priority_queue.all_indices().size(), 9); + EXPECT_EQ(priority_queue.pop(), 8); + EXPECT_EQ(priority_queue.inactive_indices().size(), 2); + EXPECT_EQ(values[priority_queue.inactive_indices()[0]], 8); + EXPECT_EQ(values[priority_queue.inactive_indices()[1]], 10); + EXPECT_EQ(priority_queue.all_indices().size(), 9); +} + +} // namespace blender::tests diff --git a/source/blender/blenlib/tests/BLI_math_rotation_test.cc b/source/blender/blenlib/tests/BLI_math_rotation_test.cc index 02257ba83dd..5a179bff3d6 100644 --- a/source/blender/blenlib/tests/BLI_math_rotation_test.cc +++ b/source/blender/blenlib/tests/BLI_math_rotation_test.cc @@ -2,6 +2,7 @@ #include "testing/testing.h" +#include "BLI_math_base.h" #include "BLI_math_rotation.h" #include <cmath> @@ -71,6 +72,12 @@ TEST(math_rotation, quat_to_mat_to_quat_bad_T83196) test_quat_to_mat_to_quat(0.0149f, 0.9996f, -0.0212f, -0.0107f); } +TEST(math_rotation, quat_to_mat_to_quat_bad_negative) +{ + /* This shouldn't produce a negative q[0]. */ + test_quat_to_mat_to_quat(0.5f - 1e-6f, 0, -sqrtf(3) / 2 - 1e-6f, 0); +} + TEST(math_rotation, quat_to_mat_to_quat_near_1000) { test_quat_to_mat_to_quat(0.9999f, 0.01f, -0.001f, -0.01f); @@ -126,3 +133,17 @@ TEST(math_rotation, quat_to_mat_to_quat_near_0001) test_quat_to_mat_to_quat(0.25f, -0.025f, -0.25f, 0.97f); test_quat_to_mat_to_quat(0.30f, -0.030f, -0.30f, 0.95f); } + +TEST(math_rotation, quat_split_swing_and_twist_negative) +{ + const float input[4] = {-0.5f, 0, sqrtf(3) / 2, 0}; + const float expected_swing[4] = {1.0f, 0, 0, 0}; + const float expected_twist[4] = {0.5f, 0, -sqrtf(3) / 2, 0}; + float swing[4], twist[4]; + + float twist_angle = quat_split_swing_and_twist(input, 1, swing, twist); + + EXPECT_NEAR(twist_angle, -M_PI * 2 / 3, FLT_EPSILON); + EXPECT_V4_NEAR(swing, expected_swing, FLT_EPSILON); + EXPECT_V4_NEAR(twist, expected_twist, FLT_EPSILON); +} diff --git a/source/blender/blenlib/tests/BLI_memory_utils_test.cc b/source/blender/blenlib/tests/BLI_memory_utils_test.cc index fcef2f8688a..23415e69b04 100644 --- a/source/blender/blenlib/tests/BLI_memory_utils_test.cc +++ b/source/blender/blenlib/tests/BLI_memory_utils_test.cc @@ -158,4 +158,15 @@ static_assert(is_convertible_pointer_v<int **, int **const>); static_assert(is_convertible_pointer_v<int **, int *const *>); static_assert(is_convertible_pointer_v<int **, int const *const *>); +static_assert(is_span_convertible_pointer_v<int *, int *>); +static_assert(is_span_convertible_pointer_v<int *, const int *>); +static_assert(!is_span_convertible_pointer_v<const int *, int *>); +static_assert(is_span_convertible_pointer_v<const int *, const int *>); +static_assert(is_span_convertible_pointer_v<const int *, const void *>); +static_assert(!is_span_convertible_pointer_v<const int *, void *>); +static_assert(is_span_convertible_pointer_v<int *, void *>); +static_assert(is_span_convertible_pointer_v<int *, const void *>); +static_assert(!is_span_convertible_pointer_v<TestBaseClass *, TestChildClass *>); +static_assert(!is_span_convertible_pointer_v<TestChildClass *, TestBaseClass *>); + } // namespace blender::tests diff --git a/source/blender/blenlib/tests/BLI_span_test.cc b/source/blender/blenlib/tests/BLI_span_test.cc index 9a8d9df7873..d1c9f312b97 100644 --- a/source/blender/blenlib/tests/BLI_span_test.cc +++ b/source/blender/blenlib/tests/BLI_span_test.cc @@ -337,4 +337,19 @@ TEST(span, MutableReverseIterator) EXPECT_EQ_ARRAY(src.data(), Span({14, 15, 16, 17}).data(), 4); } +TEST(span, constexpr_) +{ + static constexpr std::array<int, 3> src = {3, 2, 1}; + constexpr Span<int> span(src); + BLI_STATIC_ASSERT(span[2] == 1, ""); + BLI_STATIC_ASSERT(span.size() == 3, ""); + BLI_STATIC_ASSERT(span.slice(1, 2).size() == 2, ""); + BLI_STATIC_ASSERT(span.has_duplicates__linear_search() == false, ""); + + std::integral_constant<bool, span.first_index(1) == 2> ic; + BLI_STATIC_ASSERT(ic.value, ""); + + EXPECT_EQ(span.slice(1, 2).size(), 2); +} + } // namespace blender::tests diff --git a/source/blender/blenlib/tests/BLI_string_ref_test.cc b/source/blender/blenlib/tests/BLI_string_ref_test.cc index 2d488feff71..401a7bc1118 100644 --- a/source/blender/blenlib/tests/BLI_string_ref_test.cc +++ b/source/blender/blenlib/tests/BLI_string_ref_test.cc @@ -298,4 +298,12 @@ TEST(string_ref, ToStringView) EXPECT_EQ(view, "hello"); } +TEST(string_ref, constexpr_) +{ + constexpr StringRef sref("World"); + BLI_STATIC_ASSERT(sref[2] == 'r', ""); + BLI_STATIC_ASSERT(sref.size() == 5, ""); + std::array<int, static_cast<std::size_t>(sref.find_first_of('o'))> compiles = {1}; + EXPECT_EQ(compiles[0], 1); +} } // namespace blender::tests diff --git a/source/blender/blenlib/tests/BLI_string_test.cc b/source/blender/blenlib/tests/BLI_string_test.cc index 58135adbcca..88cecaa5fee 100644 --- a/source/blender/blenlib/tests/BLI_string_test.cc +++ b/source/blender/blenlib/tests/BLI_string_test.cc @@ -27,14 +27,14 @@ TEST(string, StrPartition) { const char delim[] = {'-', '.', '_', '~', '\\', '\0'}; const char *sep, *suf; - size_t pre_ln; + size_t pre_len; { const char *str = "mat.e-r_ial"; /* "mat.e-r_ial" -> "mat", '.', "e-r_ial", 3 */ - pre_ln = BLI_str_partition(str, delim, &sep, &suf); - EXPECT_EQ(pre_ln, 3); + pre_len = BLI_str_partition(str, delim, &sep, &suf); + EXPECT_EQ(pre_len, 3); EXPECT_EQ(&str[3], sep); EXPECT_STREQ("e-r_ial", suf); } @@ -44,8 +44,8 @@ TEST(string, StrPartition) const char *str = ".mate-rial--"; /* ".mate-rial--" -> "", '.', "mate-rial--", 0 */ - pre_ln = BLI_str_partition(str, delim, &sep, &suf); - EXPECT_EQ(pre_ln, 0); + pre_len = BLI_str_partition(str, delim, &sep, &suf); + EXPECT_EQ(pre_len, 0); EXPECT_EQ(&str[0], sep); EXPECT_STREQ("mate-rial--", suf); } @@ -54,8 +54,8 @@ TEST(string, StrPartition) const char *str = ".__.--_"; /* ".__.--_" -> "", '.', "__.--_", 0 */ - pre_ln = BLI_str_partition(str, delim, &sep, &suf); - EXPECT_EQ(pre_ln, 0); + pre_len = BLI_str_partition(str, delim, &sep, &suf); + EXPECT_EQ(pre_len, 0); EXPECT_EQ(&str[0], sep); EXPECT_STREQ("__.--_", suf); } @@ -64,8 +64,8 @@ TEST(string, StrPartition) const char *str = ""; /* "" -> "", NULL, NULL, 0 */ - pre_ln = BLI_str_partition(str, delim, &sep, &suf); - EXPECT_EQ(pre_ln, 0); + pre_len = BLI_str_partition(str, delim, &sep, &suf); + EXPECT_EQ(pre_len, 0); EXPECT_EQ(sep, (void *)nullptr); EXPECT_EQ(suf, (void *)nullptr); } @@ -74,8 +74,8 @@ TEST(string, StrPartition) const char *str = "material"; /* "material" -> "material", NULL, NULL, 8 */ - pre_ln = BLI_str_partition(str, delim, &sep, &suf); - EXPECT_EQ(pre_ln, 8); + pre_len = BLI_str_partition(str, delim, &sep, &suf); + EXPECT_EQ(pre_len, 8); EXPECT_EQ(sep, (void *)nullptr); EXPECT_EQ(suf, (void *)nullptr); } @@ -86,14 +86,14 @@ TEST(string, StrRPartition) { const char delim[] = {'-', '.', '_', '~', '\\', '\0'}; const char *sep, *suf; - size_t pre_ln; + size_t pre_len; { const char *str = "mat.e-r_ial"; /* "mat.e-r_ial" -> "mat.e-r", '_', "ial", 7 */ - pre_ln = BLI_str_rpartition(str, delim, &sep, &suf); - EXPECT_EQ(pre_ln, 7); + pre_len = BLI_str_rpartition(str, delim, &sep, &suf); + EXPECT_EQ(pre_len, 7); EXPECT_EQ(&str[7], sep); EXPECT_STREQ("ial", suf); } @@ -103,8 +103,8 @@ TEST(string, StrRPartition) const char *str = ".mate-rial--"; /* ".mate-rial--" -> ".mate-rial-", '-', "", 11 */ - pre_ln = BLI_str_rpartition(str, delim, &sep, &suf); - EXPECT_EQ(pre_ln, 11); + pre_len = BLI_str_rpartition(str, delim, &sep, &suf); + EXPECT_EQ(pre_len, 11); EXPECT_EQ(&str[11], sep); EXPECT_STREQ("", suf); } @@ -113,8 +113,8 @@ TEST(string, StrRPartition) const char *str = ".__.--_"; /* ".__.--_" -> ".__.--", '_', "", 6 */ - pre_ln = BLI_str_rpartition(str, delim, &sep, &suf); - EXPECT_EQ(pre_ln, 6); + pre_len = BLI_str_rpartition(str, delim, &sep, &suf); + EXPECT_EQ(pre_len, 6); EXPECT_EQ(&str[6], sep); EXPECT_STREQ("", suf); } @@ -123,8 +123,8 @@ TEST(string, StrRPartition) const char *str = ""; /* "" -> "", NULL, NULL, 0 */ - pre_ln = BLI_str_rpartition(str, delim, &sep, &suf); - EXPECT_EQ(pre_ln, 0); + pre_len = BLI_str_rpartition(str, delim, &sep, &suf); + EXPECT_EQ(pre_len, 0); EXPECT_EQ(sep, (void *)nullptr); EXPECT_EQ(suf, (void *)nullptr); } @@ -133,8 +133,8 @@ TEST(string, StrRPartition) const char *str = "material"; /* "material" -> "material", NULL, NULL, 8 */ - pre_ln = BLI_str_rpartition(str, delim, &sep, &suf); - EXPECT_EQ(pre_ln, 8); + pre_len = BLI_str_rpartition(str, delim, &sep, &suf); + EXPECT_EQ(pre_len, 8); EXPECT_EQ(sep, (void *)nullptr); EXPECT_EQ(suf, (void *)nullptr); } @@ -145,7 +145,7 @@ TEST(string, StrPartitionEx) { const char delim[] = {'-', '.', '_', '~', '\\', '\0'}; const char *sep, *suf; - size_t pre_ln; + size_t pre_len; /* Only considering 'from_right' cases here. */ @@ -153,8 +153,8 @@ TEST(string, StrPartitionEx) const char *str = "mat.e-r_ia.l"; /* "mat.e-r_ia.l" over "mat.e-r" -> "mat.e", '.', "r_ia.l", 3 */ - pre_ln = BLI_str_partition_ex(str, str + 6, delim, &sep, &suf, true); - EXPECT_EQ(pre_ln, 5); + pre_len = BLI_str_partition_ex(str, str + 6, delim, &sep, &suf, true); + EXPECT_EQ(pre_len, 5); EXPECT_EQ(&str[5], sep); EXPECT_STREQ("r_ia.l", suf); } @@ -164,8 +164,8 @@ TEST(string, StrPartitionEx) const char *str = "mate.rial"; /* "mate.rial" over "mate" -> "mate.rial", NULL, NULL, 4 */ - pre_ln = BLI_str_partition_ex(str, str + 4, delim, &sep, &suf, true); - EXPECT_EQ(pre_ln, 4); + pre_len = BLI_str_partition_ex(str, str + 4, delim, &sep, &suf, true); + EXPECT_EQ(pre_len, 4); EXPECT_EQ(sep, (void *)nullptr); EXPECT_EQ(suf, (void *)nullptr); } @@ -176,14 +176,14 @@ TEST(string, StrPartitionUtf8) { const unsigned int delim[] = {'-', '.', '_', 0x00F1 /* n tilde */, 0x262F /* ying-yang */, '\0'}; const char *sep, *suf; - size_t pre_ln; + size_t pre_len; { const char *str = "ma\xc3\xb1te-r\xe2\x98\xafial"; /* "ma\xc3\xb1te-r\xe2\x98\xafial" -> "ma", '\xc3\xb1', "te-r\xe2\x98\xafial", 2 */ - pre_ln = BLI_str_partition_utf8(str, delim, &sep, &suf); - EXPECT_EQ(pre_ln, 2); + pre_len = BLI_str_partition_utf8(str, delim, &sep, &suf); + EXPECT_EQ(pre_len, 2); EXPECT_EQ(&str[2], sep); EXPECT_STREQ("te-r\xe2\x98\xafial", suf); } @@ -193,8 +193,8 @@ TEST(string, StrPartitionUtf8) const char *str = "\xe2\x98\xafmate-rial-\xc3\xb1"; /* "\xe2\x98\xafmate-rial-\xc3\xb1" -> "", '\xe2\x98\xaf', "mate-rial-\xc3\xb1", 0 */ - pre_ln = BLI_str_partition_utf8(str, delim, &sep, &suf); - EXPECT_EQ(pre_ln, 0); + pre_len = BLI_str_partition_utf8(str, delim, &sep, &suf); + EXPECT_EQ(pre_len, 0); EXPECT_EQ(&str[0], sep); EXPECT_STREQ("mate-rial-\xc3\xb1", suf); } @@ -203,8 +203,8 @@ TEST(string, StrPartitionUtf8) const char *str = "\xe2\x98\xaf.\xc3\xb1_.--\xc3\xb1"; /* "\xe2\x98\xaf.\xc3\xb1_.--\xc3\xb1" -> "", '\xe2\x98\xaf', ".\xc3\xb1_.--\xc3\xb1", 0 */ - pre_ln = BLI_str_partition_utf8(str, delim, &sep, &suf); - EXPECT_EQ(pre_ln, 0); + pre_len = BLI_str_partition_utf8(str, delim, &sep, &suf); + EXPECT_EQ(pre_len, 0); EXPECT_EQ(&str[0], sep); EXPECT_STREQ(".\xc3\xb1_.--\xc3\xb1", suf); } @@ -213,8 +213,8 @@ TEST(string, StrPartitionUtf8) const char *str = ""; /* "" -> "", NULL, NULL, 0 */ - pre_ln = BLI_str_partition_utf8(str, delim, &sep, &suf); - EXPECT_EQ(pre_ln, 0); + pre_len = BLI_str_partition_utf8(str, delim, &sep, &suf); + EXPECT_EQ(pre_len, 0); EXPECT_EQ(sep, (void *)nullptr); EXPECT_EQ(suf, (void *)nullptr); } @@ -223,8 +223,8 @@ TEST(string, StrPartitionUtf8) const char *str = "material"; /* "material" -> "material", NULL, NULL, 8 */ - pre_ln = BLI_str_partition_utf8(str, delim, &sep, &suf); - EXPECT_EQ(pre_ln, 8); + pre_len = BLI_str_partition_utf8(str, delim, &sep, &suf); + EXPECT_EQ(pre_len, 8); EXPECT_EQ(sep, (void *)nullptr); EXPECT_EQ(suf, (void *)nullptr); } @@ -235,14 +235,14 @@ TEST(string, StrRPartitionUtf8) { const unsigned int delim[] = {'-', '.', '_', 0x00F1 /* n tilde */, 0x262F /* ying-yang */, '\0'}; const char *sep, *suf; - size_t pre_ln; + size_t pre_len; { const char *str = "ma\xc3\xb1te-r\xe2\x98\xafial"; /* "ma\xc3\xb1te-r\xe2\x98\xafial" -> "mat\xc3\xb1te-r", '\xe2\x98\xaf', "ial", 8 */ - pre_ln = BLI_str_rpartition_utf8(str, delim, &sep, &suf); - EXPECT_EQ(pre_ln, 8); + pre_len = BLI_str_rpartition_utf8(str, delim, &sep, &suf); + EXPECT_EQ(pre_len, 8); EXPECT_EQ(&str[8], sep); EXPECT_STREQ("ial", suf); } @@ -252,8 +252,8 @@ TEST(string, StrRPartitionUtf8) const char *str = "\xe2\x98\xafmate-rial-\xc3\xb1"; /* "\xe2\x98\xafmate-rial-\xc3\xb1" -> "\xe2\x98\xafmate-rial-", '\xc3\xb1', "", 13 */ - pre_ln = BLI_str_rpartition_utf8(str, delim, &sep, &suf); - EXPECT_EQ(pre_ln, 13); + pre_len = BLI_str_rpartition_utf8(str, delim, &sep, &suf); + EXPECT_EQ(pre_len, 13); EXPECT_EQ(&str[13], sep); EXPECT_STREQ("", suf); } @@ -262,8 +262,8 @@ TEST(string, StrRPartitionUtf8) const char *str = "\xe2\x98\xaf.\xc3\xb1_.--\xc3\xb1"; /* "\xe2\x98\xaf.\xc3\xb1_.--\xc3\xb1" -> "\xe2\x98\xaf.\xc3\xb1_.--", '\xc3\xb1', "", 10 */ - pre_ln = BLI_str_rpartition_utf8(str, delim, &sep, &suf); - EXPECT_EQ(pre_ln, 10); + pre_len = BLI_str_rpartition_utf8(str, delim, &sep, &suf); + EXPECT_EQ(pre_len, 10); EXPECT_EQ(&str[10], sep); EXPECT_STREQ("", suf); } @@ -272,8 +272,8 @@ TEST(string, StrRPartitionUtf8) const char *str = ""; /* "" -> "", NULL, NULL, 0 */ - pre_ln = BLI_str_rpartition_utf8(str, delim, &sep, &suf); - EXPECT_EQ(pre_ln, 0); + pre_len = BLI_str_rpartition_utf8(str, delim, &sep, &suf); + EXPECT_EQ(pre_len, 0); EXPECT_EQ(sep, (void *)nullptr); EXPECT_EQ(suf, (void *)nullptr); } @@ -282,8 +282,8 @@ TEST(string, StrRPartitionUtf8) const char *str = "material"; /* "material" -> "material", NULL, NULL, 8 */ - pre_ln = BLI_str_rpartition_utf8(str, delim, &sep, &suf); - EXPECT_EQ(pre_ln, 8); + pre_len = BLI_str_rpartition_utf8(str, delim, &sep, &suf); + EXPECT_EQ(pre_len, 8); EXPECT_EQ(sep, (void *)nullptr); EXPECT_EQ(suf, (void *)nullptr); } @@ -294,7 +294,7 @@ TEST(string, StrPartitionExUtf8) { const unsigned int delim[] = {'-', '.', '_', 0x00F1 /* n tilde */, 0x262F /* ying-yang */, '\0'}; const char *sep, *suf; - size_t pre_ln; + size_t pre_len; /* Only considering 'from_right' cases here. */ @@ -303,8 +303,8 @@ TEST(string, StrPartitionExUtf8) /* "ma\xc3\xb1te-r\xe2\x98\xafial" over * "ma\xc3\xb1te" -> "ma", '\xc3\xb1', "te-r\xe2\x98\xafial", 2 */ - pre_ln = BLI_str_partition_ex_utf8(str, str + 6, delim, &sep, &suf, true); - EXPECT_EQ(pre_ln, 2); + pre_len = BLI_str_partition_ex_utf8(str, str + 6, delim, &sep, &suf, true); + EXPECT_EQ(pre_len, 2); EXPECT_EQ(&str[2], sep); EXPECT_STREQ("te-r\xe2\x98\xafial", suf); } @@ -314,8 +314,8 @@ TEST(string, StrPartitionExUtf8) const char *str = "mate\xe2\x98\xafrial"; /* "mate\xe2\x98\xafrial" over "mate" -> "mate\xe2\x98\xafrial", NULL, NULL, 4 */ - pre_ln = BLI_str_partition_ex_utf8(str, str + 4, delim, &sep, &suf, true); - EXPECT_EQ(pre_ln, 4); + pre_len = BLI_str_partition_ex_utf8(str, str + 4, delim, &sep, &suf, true); + EXPECT_EQ(pre_len, 4); EXPECT_EQ(sep, (void *)nullptr); EXPECT_EQ(suf, (void *)nullptr); } @@ -802,3 +802,76 @@ TEST_F(StringCasecmpNatural, TextAndNumbers) testReturnsLessThanZeroForAll(negative); testReturnsMoreThanZeroForAll(positive); } + +/* BLI_str_escape, BLI_str_unescape */ + +class StringEscape : public testing::Test { + protected: + StringEscape() + { + } + + using CompareWordsArray = vector<std::array<const char *, 2>>; + + void testEscapeWords(const CompareWordsArray &items) + { + size_t dst_test_len; + char dst_test[64]; + for (const auto &item : items) { + /* Escape the string. */ + dst_test_len = BLI_str_escape(dst_test, item[0], SIZE_MAX); + EXPECT_STREQ(dst_test, item[1]); + EXPECT_EQ(dst_test_len, strlen(dst_test)); + /* Escape back. */ + dst_test_len = BLI_str_unescape(dst_test, item[1], strlen(item[1])); + EXPECT_STREQ(dst_test, item[0]); + EXPECT_EQ(dst_test_len, strlen(dst_test)); + } + } +}; + +TEST_F(StringEscape, Simple) +{ + const CompareWordsArray equal{ + {"", ""}, + {"/", "/"}, + {"'", "'"}, + {"?", "?"}, + }; + + const CompareWordsArray escaped{ + {"\\", "\\\\"}, + {"A\\", "A\\\\"}, + {"\\A", "\\\\A"}, + {"A\\B", "A\\\\B"}, + {"?", "?"}, + {"\"\\", "\\\"\\\\"}, + {"\\\"", "\\\\\\\""}, + {"\"\\\"", "\\\"\\\\\\\""}, + + {"\"\"\"", "\\\"\\\"\\\""}, + {"\\\\\\", "\\\\\\\\\\\\"}, + }; + + testEscapeWords(equal); + testEscapeWords(escaped); +} + +TEST_F(StringEscape, Control) +{ + const CompareWordsArray escaped{ + {"\n", "\\n"}, + {"\r", "\\r"}, + {"\t", "\\t"}, + {"\a", "\\a"}, + {"\b", "\\b"}, + {"\f", "\\f"}, + {"A\n", "A\\n"}, + {"\nA", "\\nA"}, + {"\n\r\t\a\b\f", "\\n\\r\\t\\a\\b\\f"}, + {"\n_\r_\t_\a_\b_\f", "\\n_\\r_\\t_\\a_\\b_\\f"}, + {"\n\\\r\\\t\\\a\\\b\\\f", "\\n\\\\\\r\\\\\\t\\\\\\a\\\\\\b\\\\\\f"}, + }; + + testEscapeWords(escaped); +} diff --git a/source/blender/blenloader/BLO_read_write.h b/source/blender/blenloader/BLO_read_write.h index c4480e2c544..ea0532d884b 100644 --- a/source/blender/blenloader/BLO_read_write.h +++ b/source/blender/blenloader/BLO_read_write.h @@ -160,6 +160,7 @@ void BLO_write_raw(BlendWriter *writer, size_t size_in_bytes, const void *data_p void BLO_write_int32_array(BlendWriter *writer, uint num, const int32_t *data_ptr); void BLO_write_uint32_array(BlendWriter *writer, uint num, const uint32_t *data_ptr); void BLO_write_float_array(BlendWriter *writer, uint num, const float *data_ptr); +void BLO_write_double_array(BlendWriter *writer, uint num, const double *data_ptr); void BLO_write_float3_array(BlendWriter *writer, uint num, const float *data_ptr); void BLO_write_pointer_array(BlendWriter *writer, uint num, const void *data_ptr); void BLO_write_string(BlendWriter *writer, const char *data_ptr); diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h index 0ab9a5e9e14..1d7c5d8a1d3 100644 --- a/source/blender/blenloader/BLO_readfile.h +++ b/source/blender/blenloader/BLO_readfile.h @@ -119,12 +119,20 @@ void BLO_blendfiledata_free(BlendFileData *bfd); /** \name BLO Blend File Handle API * \{ */ +struct BLODataBlockInfo { + char name[64]; /* MAX_NAME */ + struct AssetMetaData *asset_data; +}; + BlendHandle *BLO_blendhandle_from_file(const char *filepath, struct ReportList *reports); BlendHandle *BLO_blendhandle_from_memory(const void *mem, int memsize); struct LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh, int ofblocktype, int *tot_names); +struct LinkNode *BLO_blendhandle_get_datablock_info(BlendHandle *bh, + int ofblocktype, + int *tot_info_items); struct LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *tot_prev); struct LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh); diff --git a/source/blender/blenloader/intern/blend_validate.c b/source/blender/blenloader/intern/blend_validate.c index 2848aac2c77..c281e2fa643 100644 --- a/source/blender/blenloader/intern/blend_validate.c +++ b/source/blender/blenloader/intern/blend_validate.c @@ -148,7 +148,7 @@ bool BLO_main_validate_libraries(Main *bmain, ReportList *reports) } } - BLI_linklist_free(names, free); + BLI_linklist_freeN(names); } BLO_blendhandle_close(bh); diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c index 7a527b82e9f..296480fc2e4 100644 --- a/source/blender/blenloader/intern/readblenentry.c +++ b/source/blender/blenloader/intern/readblenentry.c @@ -40,6 +40,7 @@ #include "DNA_genfile.h" #include "DNA_sdna_types.h" +#include "BKE_icons.h" #include "BKE_idtype.h" #include "BKE_main.h" @@ -134,7 +135,7 @@ void BLO_blendhandle_print_sizes(BlendHandle *bh, void *fp) * \param bh: The blendhandle to access. * \param ofblocktype: The type of names to get. * \param tot_names: The length of the returned list. - * \return A BLI_linklist of strings. The string links should be freed with malloc. + * \return A BLI_linklist of strings. The string links should be freed with #MEM_freeN(). */ LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh, int ofblocktype, int *tot_names) { @@ -147,7 +148,7 @@ LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh, int ofblocktype, if (bhead->code == ofblocktype) { const char *idname = blo_bhead_id_name(fd, bhead); - BLI_linklist_prepend(&names, strdup(idname + 2)); + BLI_linklist_prepend(&names, BLI_strdup(idname + 2)); tot++; } else if (bhead->code == ENDB) { @@ -160,6 +161,51 @@ LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh, int ofblocktype, } /** + * Gets the names and asset-data (if ID is an asset) of all the data-blocks in a file of a certain + * type (e.g. all the scene names in a file). + * + * \param bh: The blendhandle to access. + * \param ofblocktype: The type of names to get. + * \param tot_info_items: The length of the returned list. + * \return A BLI_linklist of BLODataBlockInfo *. The links and #BLODataBlockInfo.asset_data should + * be freed with MEM_freeN. + */ +LinkNode *BLO_blendhandle_get_datablock_info(BlendHandle *bh, int ofblocktype, int *tot_info_items) +{ + FileData *fd = (FileData *)bh; + LinkNode *infos = NULL; + BHead *bhead; + int tot = 0; + + for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) { + if (bhead->code == ofblocktype) { + struct BLODataBlockInfo *info = MEM_mallocN(sizeof(*info), __func__); + const char *name = blo_bhead_id_name(fd, bhead) + 2; + + STRNCPY(info->name, name); + + /* Lastly, read asset data from the following blocks. */ + info->asset_data = blo_bhead_id_asset_data_address(fd, bhead); + if (info->asset_data) { + bhead = blo_read_asset_data_block(fd, bhead, &info->asset_data); + /* blo_read_asset_data_block() reads all DATA heads and already advances bhead to the next + * non-DATA one. Go back, so the loop doesn't skip the non-DATA head. */ + bhead = blo_bhead_prev(fd, bhead); + } + + BLI_linklist_prepend(&infos, info); + tot++; + } + else if (bhead->code == ENDB) { + break; + } + } + + *tot_info_items = tot; + return infos; +} + +/** * Gets the previews of all the data-blocks in a file of a certain type * (e.g. all the scene previews in a file). * @@ -203,6 +249,7 @@ LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *to if (looking) { if (bhead->SDNAnr == DNA_struct_find_nr(fd->filesdna, "PreviewImage")) { prv = BLO_library_read_struct(fd, bhead, "PreviewImage"); + if (prv) { memcpy(new_prv, prv, sizeof(PreviewImage)); if (prv->rect[0] && prv->w[0] && prv->h[0]) { @@ -217,6 +264,7 @@ LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *to new_prv->rect[0] = NULL; new_prv->w[0] = new_prv->h[0] = 0; } + BKE_previewimg_finish(new_prv, 0); if (prv->rect[1] && prv->w[1] && prv->h[1]) { bhead = blo_bhead_next(fd, bhead); @@ -230,6 +278,7 @@ LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *to new_prv->rect[1] = NULL; new_prv->w[1] = new_prv->h[1] = 0; } + BKE_previewimg_finish(new_prv, 1); MEM_freeN(prv); } } @@ -254,7 +303,7 @@ LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *to * (e.g. "Scene", "Mesh", "Light", etc.). * * \param bh: The blendhandle to access. - * \return A BLI_linklist of strings. The string links should be freed with malloc. + * \return A BLI_linklist of strings. The string links should be freed with #MEM_freeN(). */ LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh) { @@ -272,7 +321,7 @@ LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh) const char *str = BKE_idtype_idcode_to_name(bhead->code); if (BLI_gset_add(gathered, (void *)str)) { - BLI_linklist_prepend(&names, strdup(str)); + BLI_linklist_prepend(&names, BLI_strdup(str)); } } } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 9ce767b7ce1..b61abd4ed06 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -44,7 +44,9 @@ #define DNA_DEPRECATED_ALLOW #include "DNA_anim_types.h" +#include "DNA_asset_types.h" #include "DNA_cachefile_types.h" +#include "DNA_collection_types.h" #include "DNA_fileglobal_types.h" #include "DNA_genfile.h" #include "DNA_key_types.h" @@ -53,6 +55,7 @@ #include "DNA_packedFile_types.h" #include "DNA_sdna_types.h" #include "DNA_sound_types.h" +#include "DNA_vfont_types.h" #include "DNA_volume_types.h" #include "DNA_workspace_types.h" @@ -71,6 +74,7 @@ #include "BKE_anim_data.h" #include "BKE_animsys.h" +#include "BKE_asset.h" #include "BKE_collection.h" #include "BKE_global.h" /* for G */ #include "BKE_idprop.h" @@ -101,6 +105,9 @@ #include "BLO_readfile.h" #include "BLO_undofile.h" +#include "SEQ_clipboard.h" +#include "SEQ_iterator.h" +#include "SEQ_modifier.h" #include "SEQ_sequencer.h" #include "readfile.h" @@ -955,12 +962,21 @@ static BHead *blo_bhead_read_full(FileData *fd, BHead *thisblock) } #endif /* USE_BHEAD_READ_ON_DEMAND */ -/* Warning! Caller's responsibility to ensure given bhead **is** and ID one! */ +/* Warning! Caller's responsibility to ensure given bhead **is** an ID one! */ const char *blo_bhead_id_name(const FileData *fd, const BHead *bhead) { return (const char *)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_name_offs); } +/* Warning! Caller's responsibility to ensure given bhead **is** an ID one! */ +AssetMetaData *blo_bhead_id_asset_data_address(const FileData *fd, const BHead *bhead) +{ + BLI_assert(BKE_idtype_idcode_is_valid(bhead->code)); + return (fd->id_asset_data_offs >= 0) ? + *(AssetMetaData **)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_asset_data_offs) : + NULL; +} + static void decode_blender_header(FileData *fd) { char header[SIZEOFBLENDERHEADER], num[4]; @@ -1038,6 +1054,8 @@ static bool read_file_dna(FileData *fd, const char **r_error_message) /* used to retrieve ID names from (bhead+1) */ fd->id_name_offs = DNA_elem_offset(fd->filesdna, "ID", "char", "name[]"); BLI_assert(fd->id_name_offs != -1); + fd->id_asset_data_offs = DNA_elem_offset( + fd->filesdna, "ID", "AssetMetaData", "*asset_data"); return true; } @@ -2358,6 +2376,11 @@ static void direct_link_id_common( return; } + if (id->asset_data) { + BLO_read_data_address(reader, &id->asset_data); + BKE_asset_metadata_read(reader, id->asset_data); + } + /*link direct data of ID properties*/ if (id->properties) { BLO_read_data_address(reader, &id->properties); @@ -2583,7 +2606,7 @@ static int lib_link_seq_clipboard_cb(Sequence *seq, void *arg_pt) static void lib_link_clipboard_restore(struct IDNameLib_Map *id_map) { /* update IDs stored in sequencer clipboard */ - BKE_sequencer_base_recursive_apply(&seqbase_clipboard, lib_link_seq_clipboard_cb, id_map); + SEQ_iterator_seqbase_recursive_apply(&seqbase_clipboard, lib_link_seq_clipboard_cb, id_map); } static int lib_link_main_data_restore_cb(LibraryIDLinkCallbackData *cb_data) @@ -2731,6 +2754,7 @@ static void lib_link_workspace_layout_restore(struct IDNameLib_Map *id_map, SpaceFile *sfile = (SpaceFile *)sl; sfile->op = NULL; sfile->previews_timer = NULL; + sfile->tags = FILE_TAG_REBUILD_MAIN_FILES; } else if (sl->spacetype == SPACE_ACTION) { SpaceAction *saction = (SpaceAction *)sl; @@ -3606,6 +3630,27 @@ static BHead *read_libblock(FileData *fd, /** \} */ /* -------------------------------------------------------------------- */ +/** \name Read Asset Data + * \{ */ + +BHead *blo_read_asset_data_block(FileData *fd, BHead *bhead, AssetMetaData **r_asset_data) +{ + BLI_assert(BKE_idtype_idcode_is_valid(bhead->code)); + + bhead = read_data_into_datamap(fd, bhead, "asset-data read"); + + BlendDataReader reader = {fd}; + BLO_read_data_address(&reader, r_asset_data); + BKE_asset_metadata_read(&reader, *r_asset_data); + + oldnewmap_clear(fd->datamap); + + return bhead; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Read Global Data * \{ */ @@ -3863,6 +3908,7 @@ static BHead *read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead) BLO_read_list(reader, &user->user_menus); BLO_read_list(reader, &user->addons); BLO_read_list(reader, &user->autoexec_paths); + BLO_read_list(reader, &user->asset_libraries); LISTBASE_FOREACH (wmKeyMap *, keymap, &user->user_keymaps) { keymap->modal_items = NULL; diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h index fb950e37da8..c724cc32051 100644 --- a/source/blender/blenloader/intern/readfile.h +++ b/source/blender/blenloader/intern/readfile.h @@ -34,16 +34,13 @@ #include "zlib.h" struct BLOCacheStorage; -struct GSet; struct IDNameLib_Map; struct Key; struct MemFile; struct Object; struct OldNewMap; -struct PartEff; struct ReportList; struct UserDef; -struct View3D; typedef struct IDNameLib_Map IDNameLib_Map; @@ -112,6 +109,9 @@ typedef struct FileData { int fileversion; /** Used to retrieve ID names from (bhead+1). */ int id_name_offs; + /** Used to retrieve asset data from (bhead+1). NOTE: This may not be available in old files, + * will be -1 then! */ + int id_asset_data_offs; /** For do_versions patching. */ int globalf, fileflags; @@ -159,6 +159,8 @@ void blo_end_packed_pointer_map(FileData *fd, struct Main *oldmain); void blo_add_library_pointer_map(ListBase *old_mainlist, FileData *fd); void blo_make_old_idmap_from_main(FileData *fd, struct Main *bmain); +BHead *blo_read_asset_data_block(FileData *fd, BHead *bhead, struct AssetMetaData **r_asset_data); + void blo_cache_storage_init(FileData *fd, struct Main *bmain); void blo_cache_storage_old_bmain_clear(FileData *fd, struct Main *bmain_old); void blo_cache_storage_end(FileData *fd); @@ -170,6 +172,7 @@ BHead *blo_bhead_next(FileData *fd, BHead *thisblock); BHead *blo_bhead_prev(FileData *fd, BHead *thisblock); const char *blo_bhead_id_name(const FileData *fd, const BHead *bhead); +struct AssetMetaData *blo_bhead_id_asset_data_address(const FileData *fd, const BHead *bhead); /* do versions stuff */ diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c index c86ad639216..23f46e15f51 100644 --- a/source/blender/blenloader/intern/versioning_250.c +++ b/source/blender/blenloader/intern/versioning_250.c @@ -46,6 +46,7 @@ #include "DNA_meshdata_types.h" #include "DNA_node_types.h" #include "DNA_object_fluidsim_types.h" +#include "DNA_object_force_types.h" #include "DNA_object_types.h" #include "DNA_screen_types.h" #include "DNA_sdna_types.h" @@ -76,7 +77,7 @@ #include "BKE_sound.h" #include "BKE_texture.h" -#include "SEQ_sequencer.h" +#include "SEQ_iterator.h" #include "NOD_socket.h" diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c index c33f2a8cad5..767f24cf175 100644 --- a/source/blender/blenloader/intern/versioning_260.c +++ b/source/blender/blenloader/intern/versioning_260.c @@ -28,11 +28,13 @@ #include "DNA_camera_types.h" #include "DNA_cloth_types.h" #include "DNA_constraint_types.h" +#include "DNA_dynamicpaint_types.h" #include "DNA_fluid_types.h" #include "DNA_genfile.h" #include "DNA_key_types.h" #include "DNA_light_types.h" #include "DNA_linestyle_types.h" +#include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_fluidsim_types.h" @@ -65,7 +67,9 @@ #include "BKE_texture.h" #include "BKE_tracking.h" -#include "SEQ_sequencer.h" +#include "SEQ_iterator.h" +#include "SEQ_modifier.h" +#include "SEQ_utils.h" #ifdef WITH_FFMPEG # include "BKE_writeffmpeg.h" @@ -1497,7 +1501,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain) SequenceModifierData *smd; ColorBalanceModifierData *cbmd; - smd = BKE_sequence_modifier_new(seq, NULL, seqModifierType_ColorBalance); + smd = SEQ_modifier_new(seq, NULL, seqModifierType_ColorBalance); cbmd = (ColorBalanceModifierData *)smd; cbmd->color_balance = *strip->color_balance; @@ -1811,7 +1815,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain) seq->alpha_mode = SEQ_ALPHA_STRAIGHT; } else { - BKE_sequence_alpha_mode_from_extension(seq); + SEQ_alpha_mode_from_file_extension(seq); } } SEQ_ALL_END; diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index adc2b55b350..df9268f0da1 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -64,8 +64,10 @@ #include "BKE_scene.h" #include "BKE_screen.h" #include "BKE_tracking.h" +#include "DNA_material_types.h" -#include "SEQ_sequencer.h" +#include "SEQ_effects.h" +#include "SEQ_iterator.h" #include "BLI_listbase.h" #include "BLI_math.h" @@ -301,7 +303,9 @@ static void do_version_hue_sat_node(bNodeTree *ntree, bNode *node) /* Take care of possible animation. */ AnimData *adt = BKE_animdata_from_id(&ntree->id); if (adt != NULL && adt->action != NULL) { - const char *prefix = BLI_sprintfN("nodes[\"%s\"]", node->name); + char node_name_esc[sizeof(node->name) * 2]; + BLI_str_escape(node_name_esc, node->name, sizeof(node_name_esc)); + const char *prefix = BLI_sprintfN("nodes[\"%s\"]", node_name_esc); for (FCurve *fcu = adt->action->curves.first; fcu != NULL; fcu = fcu->next) { if (STRPREFIX(fcu->rna_path, prefix)) { anim_change_prop_name(fcu, prefix, "color_hue", "inputs[1].default_value"); @@ -1221,7 +1225,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain) } if (seq->effectdata == NULL) { - struct SeqEffectHandle effect_handle = BKE_sequence_get_effect(seq); + struct SeqEffectHandle effect_handle = SEQ_effect_handle_get(seq); effect_handle.init(seq); } diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index c2bedc54690..88493de5076 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -97,7 +97,9 @@ #include "BKE_unit.h" #include "BKE_workspace.h" -#include "SEQ_sequencer.h" +#include "SEQ_iterator.h" +#include "SEQ_modifier.h" +#include "SEQ_utils.h" /* Only for IMB_BlendMode */ #include "IMB_imbuf.h" @@ -963,7 +965,7 @@ static void do_version_curvemapping_walker(Main *bmain, void (*callback)(CurveMa if (scene->ed != NULL) { LISTBASE_FOREACH (Sequence *, seq, &scene->ed->seqbase) { LISTBASE_FOREACH (SequenceModifierData *, smd, &seq->modifiers) { - const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type); + const SequenceModifierTypeInfo *smti = SEQ_modifier_type_info_get(smd->type); if (smti) { if (smd->type == seqModifierType_Curves) { @@ -1783,7 +1785,7 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports)) static void do_versions_seq_unique_name_all_strips(Scene *sce, ListBase *seqbasep) { for (Sequence *seq = seqbasep->first; seq != NULL; seq = seq->next) { - BKE_sequence_base_unique_name_recursive(&sce->ed->seqbase, seq); + SEQ_sequence_base_unique_name_recursive(&sce->ed->seqbase, seq); if (seq->seqbase.first != NULL) { do_versions_seq_unique_name_all_strips(sce, &seq->seqbase); } diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c index 739704ce0ea..62000d4ab85 100644 --- a/source/blender/blenloader/intern/versioning_290.c +++ b/source/blender/blenloader/intern/versioning_290.c @@ -29,6 +29,7 @@ #include "DNA_anim_types.h" #include "DNA_brush_types.h" #include "DNA_cachefile_types.h" +#include "DNA_collection_types.h" #include "DNA_constraint_types.h" #include "DNA_fluid_types.h" #include "DNA_genfile.h" @@ -52,6 +53,7 @@ #include "BKE_armature.h" #include "BKE_collection.h" #include "BKE_colortools.h" +#include "BKE_cryptomatte.h" #include "BKE_fcurve.h" #include "BKE_gpencil.h" #include "BKE_lib_id.h" @@ -64,6 +66,8 @@ #include "RNA_access.h" +#include "SEQ_proxy.h" +#include "SEQ_render.h" #include "SEQ_sequencer.h" #include "BLO_readfile.h" @@ -72,6 +76,29 @@ /* Make preferences read-only, use versioning_userdef.c. */ #define U (*((const UserDef *)&U)) +static eSpaceSeq_Proxy_RenderSize get_sequencer_render_size(Main *bmain) +{ + eSpaceSeq_Proxy_RenderSize render_size = 100; + + for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { + switch (sl->spacetype) { + case SPACE_SEQ: { + SpaceSeq *sseq = (SpaceSeq *)sl; + if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) { + render_size = sseq->render_size; + break; + } + } + } + } + } + } + + return render_size; +} + /* image_size is width or height depending what RNA property is converted - X or Y. */ static void seq_convert_transform_animation(const Scene *scene, const char *path, @@ -181,7 +208,7 @@ static void seq_convert_transform_crop(const Scene *scene, /* Convert offset animation, but only if crop is not used. */ if ((seq->flag & use_transform_flag) != 0 && (seq->flag & use_crop_flag) == 0) { char name_esc[(sizeof(seq->name) - 2) * 2], *path; - BLI_strescape(name_esc, seq->name + 2, sizeof(name_esc)); + BLI_str_escape(name_esc, seq->name + 2, sizeof(name_esc)); path = BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].transform.offset_x", name_esc); seq_convert_transform_animation(scene, path, image_size_x); @@ -210,6 +237,84 @@ static void seq_convert_transform_crop_lb(const Scene *scene, } } +static void seq_convert_transform_animation_2(const Scene *scene, + const char *path, + const float scale_to_fit_factor) +{ + if (scene->adt == NULL || scene->adt->action == NULL) { + return; + } + + FCurve *fcu = BKE_fcurve_find(&scene->adt->action->curves, path, 0); + if (fcu != NULL && !BKE_fcurve_is_empty(fcu)) { + BezTriple *bezt = fcu->bezt; + for (int i = 0; i < fcu->totvert; i++, bezt++) { + /* Same math as with old_image_center_*, but simplified. */ + bezt->vec[1][1] *= scale_to_fit_factor; + } + } +} + +static void seq_convert_transform_crop_2(const Scene *scene, + Sequence *seq, + const eSpaceSeq_Proxy_RenderSize render_size) +{ + const StripElem *s_elem = SEQ_render_give_stripelem(seq, seq->start); + if (s_elem == NULL) { + return; + } + + StripCrop *c = seq->strip->crop; + StripTransform *t = seq->strip->transform; + int image_size_x = s_elem->orig_width; + int image_size_y = s_elem->orig_height; + + if (SEQ_can_use_proxy(seq, SEQ_rendersize_to_proxysize(render_size))) { + image_size_x /= SEQ_rendersize_to_scale_factor(render_size); + image_size_y /= SEQ_rendersize_to_scale_factor(render_size); + } + + /* Calculate scale factor, so image fits in preview area with original aspect ratio. */ + const float scale_to_fit_factor = MIN2((float)scene->r.xsch / (float)image_size_x, + (float)scene->r.ysch / (float)image_size_y); + t->scale_x *= scale_to_fit_factor; + t->scale_y *= scale_to_fit_factor; + c->top /= scale_to_fit_factor; + c->bottom /= scale_to_fit_factor; + c->left /= scale_to_fit_factor; + c->right /= scale_to_fit_factor; + + char name_esc[(sizeof(seq->name) - 2) * 2], *path; + BLI_str_escape(name_esc, seq->name + 2, sizeof(name_esc)); + path = BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].crop.min_x", name_esc); + seq_convert_transform_animation_2(scene, path, 1 / scale_to_fit_factor); + MEM_freeN(path); + path = BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].crop.max_x", name_esc); + seq_convert_transform_animation_2(scene, path, 1 / scale_to_fit_factor); + MEM_freeN(path); + path = BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].crop.min_y", name_esc); + seq_convert_transform_animation_2(scene, path, 1 / scale_to_fit_factor); + MEM_freeN(path); + path = BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].crop.max_x", name_esc); + seq_convert_transform_animation_2(scene, path, 1 / scale_to_fit_factor); + MEM_freeN(path); +} + +static void seq_convert_transform_crop_lb_2(const Scene *scene, + const ListBase *lb, + const eSpaceSeq_Proxy_RenderSize render_size) +{ + + LISTBASE_FOREACH (Sequence *, seq, lb) { + if (seq->type != SEQ_TYPE_SOUND_RAM) { + seq_convert_transform_crop_2(scene, seq, render_size); + } + if (seq->type == SEQ_TYPE_META) { + seq_convert_transform_crop_lb_2(scene, &seq->seqbase, render_size); + } + } +} + void do_versions_after_linking_290(Main *bmain, ReportList *UNUSED(reports)) { if (!MAIN_VERSION_ATLEAST(bmain, 290, 1)) { @@ -408,7 +513,7 @@ void do_versions_after_linking_290(Main *bmain, ReportList *UNUSED(reports)) const size_t node_name_escaped_max_length = (node_name_length * 2); char *node_name_escaped = MEM_mallocN(node_name_escaped_max_length + 1, "escaped name"); - BLI_strescape(node_name_escaped, node->name, node_name_escaped_max_length); + BLI_str_escape(node_name_escaped, node->name, node_name_escaped_max_length); char *rna_path_prefix = BLI_sprintfN("nodes[\"%s\"].inputs", node_name_escaped); BKE_animdata_fix_paths_rename_all_ex( @@ -439,25 +544,35 @@ void do_versions_after_linking_290(Main *bmain, ReportList *UNUSED(reports)) if (!MAIN_VERSION_ATLEAST(bmain, 292, 2)) { - eSpaceSeq_Proxy_RenderSize render_size = 100; + eSpaceSeq_Proxy_RenderSize render_size = get_sequencer_render_size(bmain); - for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { - LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { - LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { - switch (sl->spacetype) { - case SPACE_SEQ: { - SpaceSeq *sseq = (SpaceSeq *)sl; - render_size = sseq->render_size; - break; - } - } - } + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + if (scene->ed != NULL) { + seq_convert_transform_crop_lb(scene, &scene->ed->seqbase, render_size); } } + } + if (!MAIN_VERSION_ATLEAST(bmain, 292, 8)) { + /* Systematically rebuild posebones to ensure consistent ordering matching the one of bones in + * Armature obdata. */ + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + if (ob->type == OB_ARMATURE) { + BKE_pose_rebuild(bmain, ob, ob->data, true); + } + } + + /* Wet Paint Radius Factor */ + for (Brush *br = bmain->brushes.first; br; br = br->id.next) { + if (br->ob_mode & OB_MODE_SCULPT && br->wet_paint_radius_factor == 0.0f) { + br->wet_paint_radius_factor = 1.0f; + } + } + + eSpaceSeq_Proxy_RenderSize render_size = get_sequencer_render_size(bmain); LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { if (scene->ed != NULL) { - seq_convert_transform_crop_lb(scene, &scene->ed->seqbase, render_size); + seq_convert_transform_crop_lb_2(scene, &scene->ed->seqbase, render_size); } } } @@ -474,21 +589,6 @@ void do_versions_after_linking_290(Main *bmain, ReportList *UNUSED(reports)) */ { /* Keep this block, even when empty. */ - - /* Systematically rebuild posebones to ensure consistent ordering matching the one of bones in - * Armature obdata. */ - LISTBASE_FOREACH (Object *, ob, &bmain->objects) { - if (ob->type == OB_ARMATURE) { - BKE_pose_rebuild(bmain, ob, ob->data, true); - } - } - } - - /* Wet Paint Radius Factor */ - for (Brush *br = bmain->brushes.first; br; br = br->id.next) { - if (br->ob_mode & OB_MODE_SCULPT && br->wet_paint_radius_factor == 0.0f) { - br->wet_paint_radius_factor = 1.0f; - } } } @@ -588,6 +688,7 @@ static void do_versions_291_fcurve_handles_limit(FCurve *fcu) } } +/* NOLINTNEXTLINE: readability-function-size */ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) { UNUSED_VARS(fd); @@ -1242,6 +1343,93 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) } } + if (!MAIN_VERSION_ATLEAST(bmain, 292, 7)) { + /* Make all IDProperties used as interface of geometry node trees overridable. */ + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { + if (md->type == eModifierType_Nodes) { + NodesModifierData *nmd = (NodesModifierData *)md; + IDProperty *nmd_properties = nmd->settings.properties; + + BLI_assert(nmd_properties->type == IDP_GROUP); + LISTBASE_FOREACH (IDProperty *, nmd_socket_idprop, &nmd_properties->data.group) { + nmd_socket_idprop->flag |= IDP_FLAG_OVERRIDABLE_LIBRARY; + } + } + } + } + + /* EEVEE/Cycles Volumes consistency */ + for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { + /* Remove Volume Transmittance render pass from each view layer. */ + LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { + view_layer->eevee.render_passes &= ~EEVEE_RENDER_PASS_UNUSED_8; + } + + /* Rename Renderlayer Socket `VolumeScatterCol` to `VolumeDir` */ + if (scene->nodetree) { + LISTBASE_FOREACH (bNode *, node, &scene->nodetree->nodes) { + if (node->type == CMP_NODE_R_LAYERS) { + LISTBASE_FOREACH (bNodeSocket *, output_socket, &node->outputs) { + const char *volume_scatter = "VolumeScatterCol"; + if (STREQLEN(output_socket->name, volume_scatter, MAX_NAME)) { + BLI_strncpy(output_socket->name, RE_PASSNAME_VOLUME_LIGHT, MAX_NAME); + } + } + } + } + } + } + + /* Convert `NodeCryptomatte->storage->matte_id` to `NodeCryptomatte->storage->entries` */ + if (!DNA_struct_find(fd->filesdna, "CryptomatteEntry")) { + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + if (scene->nodetree) { + LISTBASE_FOREACH (bNode *, node, &scene->nodetree->nodes) { + if (node->type == CMP_NODE_CRYPTOMATTE) { + NodeCryptomatte *storage = (NodeCryptomatte *)node->storage; + char *matte_id = storage->matte_id; + if (matte_id == NULL || strlen(storage->matte_id) == 0) { + continue; + } + BKE_cryptomatte_matte_id_to_entries(NULL, storage, storage->matte_id); + MEM_SAFE_FREE(storage->matte_id); + } + } + } + } + } + + /* Overlay elements in the sequencer. */ + LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { + if (sl->spacetype == SPACE_SEQ) { + SpaceSeq *sseq = (SpaceSeq *)sl; + sseq->flag |= (SEQ_SHOW_STRIP_OVERLAY | SEQ_SHOW_STRIP_NAME | SEQ_SHOW_STRIP_SOURCE | + SEQ_SHOW_STRIP_DURATION); + } + } + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 292, 8)) { + LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (STREQ(node->idname, "GeometryNodeRandomAttribute")) { + STRNCPY(node->idname, "GeometryNodeAttributeRandomize"); + } + } + } + + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + if (scene->ed != NULL) { + scene->toolsettings->sequencer_tool_settings = SEQ_tool_settings_init(); + } + } + } + /** * Versioning code until next subversion bump goes here. * @@ -1253,5 +1441,26 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) */ { /* Keep this block, even when empty. */ + + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { + if (ntree->type == NTREE_GEOMETRY) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (node->type == GEO_NODE_ATTRIBUTE_MATH && node->storage == NULL) { + const int old_use_attibute_a = (1 << 0); + const int old_use_attibute_b = (1 << 1); + NodeAttributeMath *data = MEM_callocN(sizeof(NodeAttributeMath), "NodeAttributeMath"); + data->operation = NODE_MATH_ADD; + data->input_type_a = (node->custom2 & old_use_attibute_a) ? + GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE : + GEO_NODE_ATTRIBUTE_INPUT_FLOAT; + data->input_type_b = (node->custom2 & old_use_attibute_b) ? + GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE : + GEO_NODE_ATTRIBUTE_INPUT_FLOAT; + node->storage = data; + } + } + } + } + FOREACH_NODETREE_END; } } diff --git a/source/blender/blenloader/intern/versioning_cycles.c b/source/blender/blenloader/intern/versioning_cycles.c index 19e392734f0..631abe10ddc 100644 --- a/source/blender/blenloader/intern/versioning_cycles.c +++ b/source/blender/blenloader/intern/versioning_cycles.c @@ -840,12 +840,14 @@ static void update_mapping_node_fcurve_rna_path_callback(ID *UNUSED(id), fcurve->rna_path = BLI_sprintfN("%s.%s", data->nodePath, "inputs[3].default_value"); } else if (data->minimumNode && BLI_str_endswith(old_fcurve_rna_path, "max")) { - fcurve->rna_path = BLI_sprintfN( - "nodes[\"%s\"].%s", data->minimumNode->name, "inputs[1].default_value"); + char node_name_esc[sizeof(data->minimumNode->name) * 2]; + BLI_str_escape(node_name_esc, data->minimumNode->name, sizeof(node_name_esc)); + fcurve->rna_path = BLI_sprintfN("nodes[\"%s\"].%s", node_name_esc, "inputs[1].default_value"); } else if (data->maximumNode && BLI_str_endswith(old_fcurve_rna_path, "min")) { - fcurve->rna_path = BLI_sprintfN( - "nodes[\"%s\"].%s", data->maximumNode->name, "inputs[1].default_value"); + char node_name_esc[sizeof(data->maximumNode->name) * 2]; + BLI_str_escape(node_name_esc, data->maximumNode->name, sizeof(node_name_esc)); + fcurve->rna_path = BLI_sprintfN("nodes[\"%s\"].%s", node_name_esc, "inputs[1].default_value"); } if (fcurve->rna_path != old_fcurve_rna_path) { @@ -955,7 +957,10 @@ static void update_mapping_node_inputs_and_properties(bNodeTree *ntree) MEM_freeN(node->storage); node->storage = NULL; - char *nodePath = BLI_sprintfN("nodes[\"%s\"]", node->name); + char node_name_esc[sizeof(node->name) * 2]; + BLI_str_escape(node_name_esc, node->name, sizeof(node_name_esc)); + + char *nodePath = BLI_sprintfN("nodes[\"%s\"]", node_name_esc); MappingNodeFCurveCallbackData data = {nodePath, minimumNode, maximumNode}; BKE_fcurves_id_cb(&ntree->id, update_mapping_node_fcurve_rna_path_callback, &data); MEM_freeN(nodePath); diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c index 3af3c42fa5d..45eff4d9e51 100644 --- a/source/blender/blenloader/intern/versioning_defaults.c +++ b/source/blender/blenloader/intern/versioning_defaults.c @@ -37,6 +37,7 @@ #include "DNA_curveprofile_types.h" #include "DNA_gpencil_types.h" #include "DNA_light_types.h" +#include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" @@ -181,7 +182,8 @@ static void blo_update_defaults_screen(bScreen *screen, } else if (area->spacetype == SPACE_SEQ) { SpaceSeq *seq = area->spacedata.first; - seq->flag |= SEQ_SHOW_MARKERS | SEQ_SHOW_FCURVES | SEQ_ZOOM_TO_FIT; + seq->flag |= SEQ_SHOW_MARKERS | SEQ_SHOW_FCURVES | SEQ_ZOOM_TO_FIT | SEQ_SHOW_STRIP_OVERLAY | + SEQ_SHOW_STRIP_SOURCE | SEQ_SHOW_STRIP_NAME | SEQ_SHOW_STRIP_DURATION; } else if (area->spacetype == SPACE_TEXT) { /* Show syntax and line numbers in Script workspace text editor. */ @@ -745,6 +747,14 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) brush->sculpt_tool = SCULPT_TOOL_DISPLACEMENT_ERASER; } + brush_name = "Multires Displacement Smear"; + brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2); + if (!brush) { + brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); + id_us_min(&brush->id); + brush->sculpt_tool = SCULPT_TOOL_DISPLACEMENT_SMEAR; + } + /* Use the same tool icon color in the brush cursor */ for (brush = bmain->brushes.first; brush; brush = brush->id.next) { if (brush->ob_mode & OB_MODE_SCULPT) { diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c index d654a0e30bd..dc8f7a0305a 100644 --- a/source/blender/blenloader/intern/versioning_legacy.c +++ b/source/blender/blenloader/intern/versioning_legacy.c @@ -49,6 +49,7 @@ #include "DNA_nla_types.h" #include "DNA_node_types.h" #include "DNA_object_fluidsim_types.h" +#include "DNA_object_force_types.h" #include "DNA_object_types.h" #include "DNA_screen_types.h" #include "DNA_sdna_types.h" @@ -79,7 +80,7 @@ #include "BKE_particle.h" #include "BKE_pointcache.h" -#include "SEQ_sequencer.h" +#include "SEQ_iterator.h" #include "NOD_socket.h" diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c index 1d85109774c..f1572c563bf 100644 --- a/source/blender/blenloader/intern/versioning_userdef.c +++ b/source/blender/blenloader/intern/versioning_userdef.c @@ -31,6 +31,7 @@ #endif #include "DNA_anim_types.h" +#include "DNA_collection_types.h" #include "DNA_curve_types.h" #include "DNA_scene_types.h" #include "DNA_space_types.h" @@ -43,6 +44,7 @@ #include "BKE_idprop.h" #include "BKE_keyconfig.h" #include "BKE_main.h" +#include "BKE_preferences.h" #include "BLO_readfile.h" @@ -255,6 +257,10 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme) FROM_DEFAULT_V4_UCHAR(space_node.nodeclass_attribute); } + if (!USER_VERSION_ATLEAST(292, 6)) { + FROM_DEFAULT_V4_UCHAR(space_node.nodeclass_shader); + } + /** * Versioning code until next subversion bump goes here. * @@ -324,9 +330,6 @@ void blo_do_versions_userdef(UserDef *userdef) #define USER_VERSION_ATLEAST(ver, subver) MAIN_VERSION_ATLEAST(userdef, ver, subver) /* the UserDef struct is not corrected with do_versions() .... ugh! */ - if (userdef->wheellinescroll == 0) { - userdef->wheellinescroll = 3; - } if (userdef->menuthreshold1 == 0) { userdef->menuthreshold1 = 5; userdef->menuthreshold2 = 2; @@ -828,6 +831,9 @@ void blo_do_versions_userdef(UserDef *userdef) */ { /* Keep this block, even when empty. */ + if (BLI_listbase_is_empty(&userdef->asset_libraries)) { + BKE_preferences_asset_library_default_add(userdef); + } } LISTBASE_FOREACH (bTheme *, btheme, &userdef->themes) { diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 11fe240620a..0a4f2fde93f 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -93,6 +93,7 @@ /* allow writefile to use deprecated functionality (for forward compatibility code) */ #define DNA_DEPRECATED_ALLOW +#include "DNA_collection_types.h" #include "DNA_fileglobal_types.h" #include "DNA_genfile.h" #include "DNA_sdna_types.h" @@ -755,6 +756,10 @@ static void write_userdef(BlendWriter *writer, const UserDef *userdef) BLO_write_struct(writer, bPathCompare, path_cmp); } + LISTBASE_FOREACH (const bUserAssetLibrary *, asset_library, &userdef->asset_libraries) { + BLO_write_struct(writer, bUserAssetLibrary, asset_library); + } + LISTBASE_FOREACH (const uiStyle *, style, &userdef->uistyles) { BLO_write_struct(writer, uiStyle, style); } @@ -1369,6 +1374,11 @@ void BLO_write_float_array(BlendWriter *writer, uint num, const float *data_ptr) BLO_write_raw(writer, sizeof(float) * (size_t)num, data_ptr); } +void BLO_write_double_array(BlendWriter *writer, uint num, const double *data_ptr) +{ + BLO_write_raw(writer, sizeof(double) * (size_t)num, data_ptr); +} + void BLO_write_pointer_array(BlendWriter *writer, uint num, const void *data_ptr) { BLO_write_raw(writer, sizeof(void *) * (size_t)num, data_ptr); diff --git a/source/blender/bmesh/tools/bmesh_boolean.cc b/source/blender/bmesh/tools/bmesh_boolean.cc index bfb093c569f..ea5d66e195c 100644 --- a/source/blender/bmesh/tools/bmesh_boolean.cc +++ b/source/blender/bmesh/tools/bmesh_boolean.cc @@ -296,7 +296,7 @@ static bool apply_mesh_output_to_bmesh(BMesh *bm, IMesh &m_out, bool keep_hidden BMIter liter; BMLoop *l = static_cast<BMLoop *>(BM_iter_new(&liter, bm, BM_LOOPS_OF_FACE, bmf)); while (l != nullptr) { - BM_loop_interp_from_face(bm, l, orig_face, true, true); + BM_loop_interp_from_face(bm, l, orig_face, false, true); l = static_cast<BMLoop *>(BM_iter_step(&liter)); } } diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt index fec98f58261..26d29f72efb 100644 --- a/source/blender/compositor/CMakeLists.txt +++ b/source/blender/compositor/CMakeLists.txt @@ -213,6 +213,8 @@ set(SRC nodes/COM_ColorCorrectionNode.h nodes/COM_ColorCurveNode.cpp nodes/COM_ColorCurveNode.h + nodes/COM_ColorExposureNode.cpp + nodes/COM_ColorExposureNode.h nodes/COM_ColorRampNode.cpp nodes/COM_ColorRampNode.h nodes/COM_ColorToBWNode.cpp @@ -399,6 +401,8 @@ set(SRC operations/COM_ChromaMatteOperation.h operations/COM_ColorCurveOperation.cpp operations/COM_ColorCurveOperation.h + operations/COM_ColorExposureOperation.cpp + operations/COM_ColorExposureOperation.h operations/COM_ColorMatteOperation.cpp operations/COM_ColorMatteOperation.h operations/COM_ColorRampOperation.cpp diff --git a/source/blender/compositor/intern/COM_Converter.cpp b/source/blender/compositor/intern/COM_Converter.cpp index d8f67571ee5..08035940667 100644 --- a/source/blender/compositor/intern/COM_Converter.cpp +++ b/source/blender/compositor/intern/COM_Converter.cpp @@ -37,6 +37,7 @@ #include "COM_ColorBalanceNode.h" #include "COM_ColorCorrectionNode.h" #include "COM_ColorCurveNode.h" +#include "COM_ColorExposureNode.h" #include "COM_ColorMatteNode.h" #include "COM_ColorNode.h" #include "COM_ColorRampNode.h" @@ -411,6 +412,9 @@ Node *Converter::convert(bNode *b_node) case CMP_NODE_DENOISE: node = new DenoiseNode(b_node); break; + case CMP_NODE_EXPOSURE: + node = new ExposureNode(b_node); + break; } return node; } diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp b/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp index 43928f6f915..35a3314db3b 100644 --- a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp +++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp @@ -304,7 +304,7 @@ void NodeOperationBuilder::add_operation_input_constants() /* Note: unconnected inputs cached first to avoid modifying * m_operations while iterating over it */ - typedef std::vector<NodeOperationInput *> Inputs; + using Inputs = std::vector<NodeOperationInput *>; Inputs pending_inputs; for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) { NodeOperation *op = *it; diff --git a/source/blender/compositor/intern/COM_OpenCLDevice.cpp b/source/blender/compositor/intern/COM_OpenCLDevice.cpp index 51ae9d6652e..acfe800e433 100644 --- a/source/blender/compositor/intern/COM_OpenCLDevice.cpp +++ b/source/blender/compositor/intern/COM_OpenCLDevice.cpp @@ -19,7 +19,7 @@ #include "COM_OpenCLDevice.h" #include "COM_WorkScheduler.h" -typedef enum COM_VendorID { NVIDIA = 0x10DE, AMD = 0x1002 } COM_VendorID; +enum COM_VendorID { NVIDIA = 0x10DE, AMD = 0x1002 }; const cl_image_format IMAGE_FORMAT_COLOR = { CL_RGBA, CL_FLOAT, diff --git a/source/blender/compositor/nodes/COM_ColorExposureNode.cpp b/source/blender/compositor/nodes/COM_ColorExposureNode.cpp new file mode 100644 index 00000000000..10738fcfe47 --- /dev/null +++ b/source/blender/compositor/nodes/COM_ColorExposureNode.cpp @@ -0,0 +1,37 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2020, Blender Foundation. + */ + +#include "COM_ColorExposureNode.h" +#include "COM_ColorExposureOperation.h" +#include "COM_ExecutionSystem.h" + +ExposureNode::ExposureNode(bNode *editorNode) : Node(editorNode) +{ + /* pass */ +} + +void ExposureNode::convertToOperations(NodeConverter &converter, + const CompositorContext & /*context*/) const +{ + ExposureOperation *operation = new ExposureOperation(); + converter.addOperation(operation); + + converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0)); + converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); + converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket(0)); +} diff --git a/source/blender/compositor/nodes/COM_ColorExposureNode.h b/source/blender/compositor/nodes/COM_ColorExposureNode.h new file mode 100644 index 00000000000..18aefb7eae4 --- /dev/null +++ b/source/blender/compositor/nodes/COM_ColorExposureNode.h @@ -0,0 +1,34 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2020, Blender Foundation. + */ + +#ifndef __COM_EXPOSURENODE_H__ +#define __COM_EXPOSURENODE_H__ + +#include "COM_Node.h" + +/** + * \brief ExposureNode + * \ingroup Node + */ +class ExposureNode : public Node { + public: + ExposureNode(bNode *editorNode); + void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; +}; + +#endif diff --git a/source/blender/compositor/nodes/COM_CryptomatteNode.cpp b/source/blender/compositor/nodes/COM_CryptomatteNode.cpp index 8cc6b933759..7ca4e1f76fc 100644 --- a/source/blender/compositor/nodes/COM_CryptomatteNode.cpp +++ b/source/blender/compositor/nodes/COM_CryptomatteNode.cpp @@ -17,12 +17,15 @@ */ #include "COM_CryptomatteNode.h" -#include "BLI_assert.h" -#include "BLI_hash_mm3.h" -#include "BLI_string.h" #include "COM_ConvertOperation.h" #include "COM_CryptomatteOperation.h" #include "COM_SetAlphaOperation.h" + +#include "BLI_assert.h" +#include "BLI_hash_mm3.h" +#include "BLI_listbase.h" +#include "BLI_string.h" + #include <iterator> CryptomatteNode::CryptomatteNode(bNode *editorNode) : Node(editorNode) @@ -30,24 +33,6 @@ CryptomatteNode::CryptomatteNode(bNode *editorNode) : Node(editorNode) /* pass */ } -/* This is taken from the Cryptomatte specification 1.0. */ -static inline float hash_to_float(uint32_t hash) -{ - uint32_t mantissa = hash & ((1 << 23) - 1); - uint32_t exponent = (hash >> 23) & ((1 << 8) - 1); - exponent = max(exponent, (uint32_t)1); - exponent = min(exponent, (uint32_t)254); - exponent = exponent << 23; - uint32_t sign = (hash >> 31); - sign = sign << 31; - uint32_t float_bits = sign | exponent | mantissa; - float f; - /* Bit casting relies on equal size for both types. */ - BLI_STATIC_ASSERT(sizeof(float) == sizeof(uint32_t), "float and uint32_t are not the same size") - ::memcpy(&f, &float_bits, sizeof(float)); - return f; -} - void CryptomatteNode::convertToOperations(NodeConverter &converter, const CompositorContext & /*context*/) const { @@ -61,30 +46,8 @@ void CryptomatteNode::convertToOperations(NodeConverter &converter, CryptomatteOperation *operation = new CryptomatteOperation(getNumberOfInputSockets() - 1); if (cryptoMatteSettings) { - if (cryptoMatteSettings->matte_id) { - /* Split the string by commas, ignoring white space. */ - std::string input = cryptoMatteSettings->matte_id; - std::istringstream ss(input); - while (ss.good()) { - std::string token; - getline(ss, token, ','); - /* Ignore empty tokens. */ - if (token.length() > 0) { - size_t first = token.find_first_not_of(' '); - size_t last = token.find_last_not_of(' '); - if (first == std::string::npos || last == std::string::npos) { - break; - } - token = token.substr(first, (last - first + 1)); - if (*token.begin() == '<' && *(--token.end()) == '>') { - operation->addObjectIndex(atof(token.substr(1, token.length() - 2).c_str())); - } - else { - uint32_t hash = BLI_hash_mm3((const unsigned char *)token.c_str(), token.length(), 0); - operation->addObjectIndex(hash_to_float(hash)); - } - } - } + LISTBASE_FOREACH (CryptomatteEntry *, cryptomatte_entry, &cryptoMatteSettings->entries) { + operation->addObjectIndex(cryptomatte_entry->encoded_hash); } } diff --git a/source/blender/compositor/operations/COM_ColorExposureOperation.cpp b/source/blender/compositor/operations/COM_ColorExposureOperation.cpp new file mode 100644 index 00000000000..8a475432cc8 --- /dev/null +++ b/source/blender/compositor/operations/COM_ColorExposureOperation.cpp @@ -0,0 +1,57 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2020, Blender Foundation. + */ + +#include "COM_ColorExposureOperation.h" + +ExposureOperation::ExposureOperation() : NodeOperation() +{ + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_VALUE); + this->addOutputSocket(COM_DT_COLOR); + this->m_inputProgram = NULL; +} + +void ExposureOperation::initExecution() +{ + this->m_inputProgram = this->getInputSocketReader(0); + this->m_inputExposureProgram = this->getInputSocketReader(1); +} + +void ExposureOperation::executePixelSampled(float output[4], + float x, + float y, + PixelSampler sampler) +{ + float inputValue[4]; + float inputExposure[4]; + this->m_inputProgram->readSampled(inputValue, x, y, sampler); + this->m_inputExposureProgram->readSampled(inputExposure, x, y, sampler); + const float exposure = pow(2, inputExposure[0]); + + output[0] = inputValue[0] * exposure; + output[1] = inputValue[1] * exposure; + output[2] = inputValue[2] * exposure; + + output[3] = inputValue[3]; +} + +void ExposureOperation::deinitExecution() +{ + this->m_inputProgram = NULL; + this->m_inputExposureProgram = NULL; +} diff --git a/source/blender/compositor/operations/COM_ColorExposureOperation.h b/source/blender/compositor/operations/COM_ColorExposureOperation.h new file mode 100644 index 00000000000..a65d5acbe6c --- /dev/null +++ b/source/blender/compositor/operations/COM_ColorExposureOperation.h @@ -0,0 +1,49 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2020, Blender Foundation. + */ + +#ifndef __COM_COLOREXPOSUREOPERATION_H__ +#define __COM_COLOREXPOSUREOPERATION_H__ +#include "COM_NodeOperation.h" + +class ExposureOperation : public NodeOperation { + private: + /** + * Cached reference to the inputProgram + */ + SocketReader *m_inputProgram; + SocketReader *m_inputExposureProgram; + + public: + ExposureOperation(); + + /** + * the inner loop of this program + */ + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + + /** + * Initialize the execution + */ + void initExecution(); + + /** + * Deinitialize the execution + */ + void deinitExecution(); +}; +#endif diff --git a/source/blender/compositor/operations/COM_DilateErodeOperation.cpp b/source/blender/compositor/operations/COM_DilateErodeOperation.cpp index 74f5fceacfb..b2dfb558028 100644 --- a/source/blender/compositor/operations/COM_DilateErodeOperation.cpp +++ b/source/blender/compositor/operations/COM_DilateErodeOperation.cpp @@ -330,11 +330,11 @@ void DilateStepOperation::initExecution() } // small helper to pass data from initializeTileData to executePixel -typedef struct tile_info { +struct tile_info { rcti rect; int width; float *buffer; -} tile_info; +}; static tile_info *create_cache(int xmin, int xmax, int ymin, int ymax) { diff --git a/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp b/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp index acc1dddacdd..362905761bb 100644 --- a/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp +++ b/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp @@ -23,7 +23,7 @@ * 2D Fast Hartley Transform, used for convolution */ -typedef float fREAL; +using fREAL = float; // returns next highest power of 2 of x, as well its log2 in L2 static unsigned int nextPow2(unsigned int x, unsigned int *L2) diff --git a/source/blender/compositor/operations/COM_VectorBlurOperation.cpp b/source/blender/compositor/operations/COM_VectorBlurOperation.cpp index 6254f93472e..f7b908deaf4 100644 --- a/source/blender/compositor/operations/COM_VectorBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_VectorBlurOperation.cpp @@ -141,7 +141,7 @@ void VectorBlurOperation::generateVectorBlur(float *data, /* ****************** Spans ******************************* */ /* span fill in method, is also used to localize data for zbuffering */ -typedef struct ZSpan { +struct ZSpan { /* range for clipping */ int rectx, recty; @@ -157,8 +157,7 @@ typedef struct ZSpan { int *rectz; DrawBufPixel *rectdraw; float clipcrop; - -} ZSpan; +}; /* each zbuffer has coordinates transformed to local rect coordinates, so we can simply clip */ void zbuf_alloc_span(ZSpan *zspan, int rectx, int recty, float clipcrop) diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h index f894bdabba4..4e618d8625d 100644 --- a/source/blender/depsgraph/DEG_depsgraph_build.h +++ b/source/blender/depsgraph/DEG_depsgraph_build.h @@ -39,7 +39,6 @@ struct Main; struct Object; struct Scene; struct Simulation; -struct ViewLayer; struct bNodeTree; #include "BLI_sys_types.h" diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 5af70305e13..eb20dfb69a2 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -109,7 +109,7 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" -#include "SEQ_sequencer.h" +#include "SEQ_iterator.h" #include "intern/builder/deg_builder.h" #include "intern/depsgraph.h" @@ -1483,6 +1483,9 @@ void DepsgraphNodeBuilder::build_nodetree_socket(bNodeSocket *socket) else if (socket->type == SOCK_IMAGE) { build_id((ID *)((bNodeSocketValueImage *)socket->default_value)->value); } + else if (socket->type == SOCK_COLLECTION) { + build_id((ID *)((bNodeSocketValueCollection *)socket->default_value)->value); + } } void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc index c7669b9fecb..b1fd86f13bc 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc @@ -34,6 +34,7 @@ #include "BLI_string.h" #include "BLI_utildefines.h" +#include "DNA_collection_types.h" #include "DNA_freestyle_types.h" #include "DNA_layer_types.h" #include "DNA_linestyle_types.h" diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 11d34782569..df48cb91ce7 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -39,6 +39,7 @@ #include "DNA_armature_types.h" #include "DNA_cachefile_types.h" #include "DNA_camera_types.h" +#include "DNA_cloth_types.h" #include "DNA_collection_types.h" #include "DNA_constraint_types.h" #include "DNA_curve_types.h" @@ -98,7 +99,7 @@ #include "RNA_access.h" #include "RNA_types.h" -#include "SEQ_sequencer.h" +#include "SEQ_iterator.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" @@ -2316,6 +2317,12 @@ void DepsgraphRelationBuilder::build_nodetree_socket(bNodeSocket *socket) build_image(image); } } + else if (socket->type == SOCK_COLLECTION) { + Collection *collection = ((bNodeSocketValueCollection *)socket->default_value)->value; + if (collection != nullptr) { + build_collection(nullptr, nullptr, collection); + } + } } void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h index cbfb51c59a6..5587379089c 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h @@ -45,7 +45,6 @@ #include "intern/node/deg_node_id.h" #include "intern/node/deg_node_operation.h" -struct Base; struct CacheFile; struct Camera; struct Collection; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc index 8df8d4914c3..24876049942 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc @@ -34,6 +34,7 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" +#include "DNA_collection_types.h" #include "DNA_linestyle_types.h" #include "DNA_node_types.h" #include "DNA_object_types.h" diff --git a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc index 1c050edc386..6ce7cc0837b 100644 --- a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc +++ b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc @@ -47,7 +47,7 @@ namespace deg = blender::deg; namespace blender::deg { namespace { -typedef deque<OperationNode *> TraversalQueue; +using TraversalQueue = deque<OperationNode *>; using DEGForeachOperation = void (*)(OperationNode *, void *); diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc index b92bf475f49..e472d82f2ee 100644 --- a/source/blender/depsgraph/intern/depsgraph_query_iter.cc +++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc @@ -136,8 +136,8 @@ bool deg_iterator_components_step(BLI_Iterator *iter) return false; } - if (data->geometry_component_owner->type != OB_POINTCLOUD) { - /* Only point clouds support multiple geometry components currently. */ + if (data->geometry_component_owner->runtime.geometry_set_eval == nullptr) { + /* Return the object itself, if it does not have a geometry set yet. */ iter->current = data->geometry_component_owner; data->geometry_component_owner = nullptr; return true; @@ -149,10 +149,16 @@ bool deg_iterator_components_step(BLI_Iterator *iter) return false; } + /* The mesh component. */ if (data->geometry_component_id == 0) { data->geometry_component_id++; - /* The mesh component. */ + /* Don't use a temporary object for this component, when the owner is a mesh object. */ + if (data->geometry_component_owner->type == OB_MESH) { + iter->current = data->geometry_component_owner; + return true; + } + const Mesh *mesh = geometry_set->get_mesh_for_read(); if (mesh != nullptr) { Object *temp_object = &data->temp_geometry_component_object; @@ -164,10 +170,17 @@ bool deg_iterator_components_step(BLI_Iterator *iter) return true; } } + + /* The pointcloud component. */ if (data->geometry_component_id == 1) { data->geometry_component_id++; - /* The pointcloud component. */ + /* Don't use a temporary object for this component, when the owner is a point cloud object. */ + if (data->geometry_component_owner->type == OB_POINTCLOUD) { + iter->current = data->geometry_component_owner; + return true; + } + const PointCloud *pointcloud = geometry_set->get_pointcloud_for_read(); if (pointcloud != nullptr) { Object *temp_object = &data->temp_geometry_component_object; @@ -179,6 +192,7 @@ bool deg_iterator_components_step(BLI_Iterator *iter) return true; } } + data->geometry_component_owner = nullptr; return false; } diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc index cff7292abd4..2544bb1642c 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc @@ -92,7 +92,7 @@ #include "BKE_pointcache.h" #include "BKE_sound.h" -#include "SEQ_sequencer.h" +#include "SEQ_relations.h" #include "intern/builder/deg_builder.h" #include "intern/builder/deg_builder_nodes.h" @@ -322,7 +322,7 @@ bool scene_copy_inplace_no_main(const Scene *scene, Scene *new_scene) const ID *id_for_copy = &scene->id; if (G.debug & G_DEBUG_DEPSGRAPH_UUID) { - BKE_sequencer_check_uuids_unique_and_report(scene); + SEQ_relations_check_uuids_unique_and_report(scene); } #ifdef NESTED_ID_NASTY_WORKAROUND diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc index fa7cfb305ee..1b24e2b7ad2 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc @@ -82,7 +82,7 @@ enum { COMPONENT_STATE_DONE = 2, }; -typedef deque<OperationNode *> FlushQueue; +using FlushQueue = deque<OperationNode *>; namespace { diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.h b/source/blender/depsgraph/intern/eval/deg_eval_flush.h index 1f58c54dbf4..ec661360fdf 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_flush.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.h @@ -25,8 +25,6 @@ #pragma once -struct Main; - namespace blender { namespace deg { diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.cc index c0e284a930e..34c23740730 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.cc @@ -30,7 +30,7 @@ #include "BKE_sound.h" -#include "SEQ_sequencer.h" +#include "SEQ_iterator.h" namespace blender::deg { diff --git a/source/blender/draw/engines/eevee/eevee_cryptomatte.c b/source/blender/draw/engines/eevee/eevee_cryptomatte.c index 44ff86b3333..9150de7184a 100644 --- a/source/blender/draw/engines/eevee/eevee_cryptomatte.c +++ b/source/blender/draw/engines/eevee/eevee_cryptomatte.c @@ -125,7 +125,7 @@ void EEVEE_cryptomatte_renderpasses_init(EEVEE_Data *vedata) return; } if (eevee_cryptomatte_active_layers(view_layer) != 0) { - g_data->render_passes |= EEVEE_RENDER_PASS_CRYPTOMATTE; + g_data->render_passes |= EEVEE_RENDER_PASS_CRYPTOMATTE | EEVEE_RENDER_PASS_VOLUME_LIGHT; g_data->cryptomatte_accurate_mode = (view_layer->cryptomatte_flag & VIEW_LAYER_CRYPTOMATTE_ACCURATE) != 0; } @@ -137,7 +137,8 @@ void EEVEE_cryptomatte_output_init(EEVEE_ViewLayerData *UNUSED(sldata), { EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_TextureList *txl = vedata->txl; - EEVEE_PrivateData *g_data = vedata->stl->g_data; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_PrivateData *g_data = stl->g_data; DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); const DRWContextState *draw_ctx = DRW_context_state_get(); @@ -303,7 +304,7 @@ void EEVEE_cryptomatte_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *s GPUBatch *geom = DRW_cache_object_surface_get(ob); if (geom) { DRWShadingGroup *grp = eevee_cryptomatte_shading_group_create( - vedata, sldata, ob, false, NULL); + vedata, sldata, ob, NULL, false); DRW_shgroup_call(grp, geom, ob); } } @@ -469,6 +470,8 @@ static void eevee_cryptomatte_postprocess_weights(EEVEE_Data *vedata) { EEVEE_StorageList *stl = vedata->stl; EEVEE_PrivateData *g_data = stl->g_data; + EEVEE_EffectsInfo *effects = stl->effects; + EEVEE_TextureList *txl = vedata->txl; const DRWContextState *draw_ctx = DRW_context_state_get(); const ViewLayer *view_layer = draw_ctx->view_layer; const int num_cryptomatte_layers = eevee_cryptomatte_layers_count(view_layer); @@ -478,11 +481,25 @@ static void eevee_cryptomatte_postprocess_weights(EEVEE_Data *vedata) EEVEE_CryptomatteSample *accum_buffer = g_data->cryptomatte_accum_buffer; BLI_assert(accum_buffer); + float *volumetric_transmittance_buffer = NULL; + if ((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) { + volumetric_transmittance_buffer = GPU_texture_read( + txl->volume_transmittance_accum, GPU_DATA_FLOAT, 0); + } + const int num_samples = effects->taa_current_sample; + int accum_pixel_index = 0; int accum_pixel_stride = eevee_cryptomatte_pixel_stride(view_layer); for (int pixel_index = 0; pixel_index < buffer_size; pixel_index++, accum_pixel_index += accum_pixel_stride) { + float coverage = 1.0f; + if (volumetric_transmittance_buffer != NULL) { + coverage = (volumetric_transmittance_buffer[pixel_index * 4] + + volumetric_transmittance_buffer[pixel_index * 4 + 1] + + volumetric_transmittance_buffer[pixel_index * 4 + 2]) / + (3.0f * num_samples); + } for (int layer = 0; layer < num_cryptomatte_layers; layer++) { const int layer_offset = eevee_cryptomatte_layer_offset(view_layer, layer); /* Calculate the total weight of the sample. */ @@ -493,24 +510,40 @@ static void eevee_cryptomatte_postprocess_weights(EEVEE_Data *vedata) } BLI_assert(total_weight > 0.0f); - float total_weight_inv = 1.0f / total_weight; - for (int level = 0; level < num_levels; level++) { - EEVEE_CryptomatteSample *sample = &accum_buffer[accum_pixel_index + layer_offset + level]; - /* Remove background samples. These samples were used to determine the correct weight - * but won't be part of the final result. */ - if (sample->hash == 0.0f) { + float total_weight_inv = coverage / total_weight; + if (total_weight_inv > 0.0f) { + for (int level = 0; level < num_levels; level++) { + EEVEE_CryptomatteSample *sample = + &accum_buffer[accum_pixel_index + layer_offset + level]; + /* Remove background samples. These samples were used to determine the correct weight + * but won't be part of the final result. */ + if (sample->hash == 0.0f) { + sample->weight = 0.0f; + } + sample->weight *= total_weight_inv; + } + + /* Sort accum buffer by coverage of each sample. */ + qsort(&accum_buffer[accum_pixel_index + layer_offset], + num_levels, + sizeof(EEVEE_CryptomatteSample), + eevee_cryptomatte_sample_cmp_reverse); + } + else { + /* This pixel doesn't have any weight, so clear it fully. */ + for (int level = 0; level < num_levels; level++) { + EEVEE_CryptomatteSample *sample = + &accum_buffer[accum_pixel_index + layer_offset + level]; sample->weight = 0.0f; + sample->hash = 0.0f; } - sample->weight *= total_weight_inv; } - - /* Sort accum buffer by coverage of each sample. */ - qsort(&accum_buffer[accum_pixel_index + layer_offset], - num_levels, - sizeof(EEVEE_CryptomatteSample), - eevee_cryptomatte_sample_cmp_reverse); } } + + if (volumetric_transmittance_buffer) { + MEM_freeN(volumetric_transmittance_buffer); + } } /* Extract cryptomatte layer from the cryptomatte_accum_buffer to render passes. */ diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.h b/source/blender/draw/engines/eevee/eevee_lightcache.h index 17392c0de0b..fde0c80ab37 100644 --- a/source/blender/draw/engines/eevee/eevee_lightcache.h +++ b/source/blender/draw/engines/eevee/eevee_lightcache.h @@ -24,14 +24,14 @@ #include "BLI_sys_types.h" /* for bool */ +struct BlendDataReader; +struct BlendWriter; struct EEVEE_Data; struct EEVEE_ViewLayerData; struct LightCache; struct Scene; struct SceneEEVEE; struct ViewLayer; -struct BlendWriter; -struct BlendDataReader; /* Light Bake */ struct wmJob *EEVEE_lightbake_job_create(struct wmWindowManager *wm, diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index a6a480ca967..5bf8cab1b22 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -989,6 +989,7 @@ typedef struct EEVEE_PrivateData { GPUTexture *renderpass_input; GPUTexture *renderpass_col_input; GPUTexture *renderpass_light_input; + GPUTexture *renderpass_transmittance_input; /* Renderpass ubo reference used by material pass. */ struct GPUUniformBuf *renderpass_ubo; /** For rendering shadows. */ diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c index 2b2ff2e5c90..2a01aeefce8 100644 --- a/source/blender/draw/engines/eevee/eevee_render.c +++ b/source/blender/draw/engines/eevee/eevee_render.c @@ -461,21 +461,13 @@ static void eevee_render_result_environment(RenderLayer *rl, EEVEE_RENDER_RESULT_MATERIAL_PASS(ENVIRONMENT, ENVIRONMENT) } -static void eevee_render_result_volume_scatter(RenderLayer *rl, - const char *viewname, - const rcti *rect, - EEVEE_Data *vedata, - EEVEE_ViewLayerData *sldata) -{ - EEVEE_RENDER_RESULT_MATERIAL_PASS(VOLUME_SCATTER, VOLUME_SCATTER) -} -static void eevee_render_result_volume_transmittance(RenderLayer *rl, - const char *viewname, - const rcti *rect, - EEVEE_Data *vedata, - EEVEE_ViewLayerData *sldata) +static void eevee_render_result_volume_light(RenderLayer *rl, + const char *viewname, + const rcti *rect, + EEVEE_Data *vedata, + EEVEE_ViewLayerData *sldata) { - EEVEE_RENDER_RESULT_MATERIAL_PASS(VOLUME_TRANSMITTANCE, VOLUME_TRANSMITTANCE) + EEVEE_RENDER_RESULT_MATERIAL_PASS(VOLUME_LIGHT, VOLUME_LIGHT) } static void eevee_render_result_aovs(RenderLayer *rl, @@ -696,8 +688,7 @@ void EEVEE_render_read_result(EEVEE_Data *vedata, eevee_render_result_emission(rl, viewname, rect, vedata, sldata); eevee_render_result_environment(rl, viewname, rect, vedata, sldata); eevee_render_result_bloom(rl, viewname, rect, vedata, sldata); - eevee_render_result_volume_scatter(rl, viewname, rect, vedata, sldata); - eevee_render_result_volume_transmittance(rl, viewname, rect, vedata, sldata); + eevee_render_result_volume_light(rl, viewname, rect, vedata, sldata); eevee_render_result_aovs(rl, viewname, rect, vedata, sldata); eevee_render_result_cryptomatte(rl, viewname, rect, vedata, sldata); } @@ -730,8 +721,7 @@ void EEVEE_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *v CHECK_PASS_LEGACY(GLOSSY_DIRECT, SOCK_RGBA, 3, "RGB"); CHECK_PASS_LEGACY(EMIT, SOCK_RGBA, 3, "RGB"); CHECK_PASS_LEGACY(ENVIRONMENT, SOCK_RGBA, 3, "RGB"); - CHECK_PASS_EEVEE(VOLUME_SCATTER, SOCK_RGBA, 3, "RGB"); - CHECK_PASS_EEVEE(VOLUME_TRANSMITTANCE, SOCK_RGBA, 3, "RGB"); + CHECK_PASS_EEVEE(VOLUME_LIGHT, SOCK_RGBA, 3, "RGB"); CHECK_PASS_EEVEE(BLOOM, SOCK_RGBA, 3, "RGB"); LISTBASE_FOREACH (ViewLayerAOV *, aov, &view_layer->aovs) { diff --git a/source/blender/draw/engines/eevee/eevee_renderpasses.c b/source/blender/draw/engines/eevee/eevee_renderpasses.c index e7a03c678a8..dff3b437953 100644 --- a/source/blender/draw/engines/eevee/eevee_renderpasses.c +++ b/source/blender/draw/engines/eevee/eevee_renderpasses.c @@ -44,14 +44,14 @@ typedef enum eRenderPassPostProcessType { PASS_POST_AO = 6, PASS_POST_NORMAL = 7, PASS_POST_TWO_LIGHT_BUFFERS = 8, + PASS_POST_ACCUMULATED_TRANSMITTANCE_COLOR = 9, } eRenderPassPostProcessType; /* bitmask containing all renderpasses that need post-processing */ #define EEVEE_RENDERPASSES_WITH_POST_PROCESSING \ (EEVEE_RENDER_PASS_Z | EEVEE_RENDER_PASS_MIST | EEVEE_RENDER_PASS_NORMAL | \ - EEVEE_RENDER_PASS_AO | EEVEE_RENDER_PASS_BLOOM | EEVEE_RENDER_PASS_VOLUME_SCATTER | \ - EEVEE_RENDER_PASS_VOLUME_TRANSMITTANCE | EEVEE_RENDER_PASS_SHADOW | \ - EEVEE_RENDERPASSES_MATERIAL) + EEVEE_RENDER_PASS_AO | EEVEE_RENDER_PASS_BLOOM | EEVEE_RENDER_PASS_VOLUME_LIGHT | \ + EEVEE_RENDER_PASS_SHADOW | EEVEE_RENDERPASSES_MATERIAL) #define EEVEE_RENDERPASSES_ALL \ (EEVEE_RENDERPASSES_WITH_POST_PROCESSING | EEVEE_RENDER_PASS_COMBINED) @@ -64,7 +64,10 @@ typedef enum eRenderPassPostProcessType { EEVEE_RENDER_PASS_BLOOM) #define EEVEE_RENDERPASSES_LIGHT_PASS \ (EEVEE_RENDER_PASS_DIFFUSE_LIGHT | EEVEE_RENDER_PASS_SPECULAR_LIGHT) - +/* Render passes that uses volume transmittance when available */ +#define EEVEE_RENDERPASSES_USES_TRANSMITTANCE \ + (EEVEE_RENDER_PASS_DIFFUSE_COLOR | EEVEE_RENDER_PASS_SPECULAR_COLOR | EEVEE_RENDER_PASS_EMIT | \ + EEVEE_RENDER_PASS_ENVIRONMENT) bool EEVEE_renderpasses_only_first_sample_pass_active(EEVEE_Data *vedata) { EEVEE_StorageList *stl = vedata->stl; @@ -147,6 +150,18 @@ void EEVEE_renderpasses_init(EEVEE_Data *vedata) EEVEE_cryptomatte_renderpasses_init(vedata); } +BLI_INLINE bool eevee_renderpasses_volumetric_active(const EEVEE_EffectsInfo *effects, + const EEVEE_PrivateData *g_data) +{ + if (effects->enabled_effects & EFFECT_VOLUMETRIC) { + if (g_data->render_passes & + (EEVEE_RENDER_PASS_VOLUME_LIGHT | EEVEE_RENDERPASSES_USES_TRANSMITTANCE)) { + return true; + } + } + return false; +} + void EEVEE_renderpasses_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, uint tot_samples) @@ -189,8 +204,7 @@ void EEVEE_renderpasses_output_init(EEVEE_ViewLayerData *sldata, EEVEE_bloom_output_init(sldata, vedata, tot_samples); } - if ((g_data->render_passes & - (EEVEE_RENDER_PASS_VOLUME_TRANSMITTANCE | EEVEE_RENDER_PASS_VOLUME_SCATTER)) != 0) { + if (eevee_renderpasses_volumetric_active(effects, g_data)) { EEVEE_volumes_output_init(sldata, vedata, tot_samples); } @@ -198,6 +212,7 @@ void EEVEE_renderpasses_output_init(EEVEE_ViewLayerData *sldata, g_data->renderpass_input = txl->color; g_data->renderpass_col_input = txl->color; g_data->renderpass_light_input = txl->color; + g_data->renderpass_transmittance_input = txl->color; } else { /* Free unneeded memory */ @@ -227,6 +242,8 @@ void EEVEE_renderpasses_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ve DRW_shgroup_uniform_texture_ref(grp, "inputColorBuffer", &g_data->renderpass_col_input); DRW_shgroup_uniform_texture_ref( grp, "inputSecondLightBuffer", &g_data->renderpass_light_input); + DRW_shgroup_uniform_texture_ref( + grp, "inputTransmittanceBuffer", &g_data->renderpass_transmittance_input); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); DRW_shgroup_uniform_block_ref(grp, "common_block", &sldata->common_ubo); DRW_shgroup_uniform_block_ref(grp, "renderpass_block", &sldata->renderpass_ubo.combined); @@ -265,6 +282,19 @@ void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *UNUSED(sldata), g_data->renderpass_current_sample = current_sample; g_data->renderpass_type = renderpass_type; g_data->renderpass_postprocess = PASS_POST_UNDEFINED; + const bool volumetric_active = eevee_renderpasses_volumetric_active(effects, g_data); + eRenderPassPostProcessType default_color_pass_type = + volumetric_active ? PASS_POST_ACCUMULATED_TRANSMITTANCE_COLOR : PASS_POST_ACCUMULATED_COLOR; + g_data->renderpass_transmittance_input = volumetric_active ? txl->volume_transmittance_accum : + txl->color; + + if (!volumetric_active && renderpass_type == EEVEE_RENDER_PASS_VOLUME_LIGHT) { + /* Early exit: Volumetric effect is off, but the volume light pass was requested. */ + static float clear_col[4] = {0.0f}; + GPU_framebuffer_bind(fbl->renderpass_fb); + GPU_framebuffer_clear_color(fbl->renderpass_fb, clear_col); + return; + } switch (renderpass_type) { case EEVEE_RENDER_PASS_Z: { @@ -286,38 +316,33 @@ void EEVEE_renderpasses_postprocess(EEVEE_ViewLayerData *UNUSED(sldata), g_data->renderpass_input = txl->mist_accum; break; } - case EEVEE_RENDER_PASS_VOLUME_SCATTER: { + case EEVEE_RENDER_PASS_VOLUME_LIGHT: { g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_COLOR; g_data->renderpass_input = txl->volume_scatter_accum; break; } - case EEVEE_RENDER_PASS_VOLUME_TRANSMITTANCE: { - g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_COLOR; - g_data->renderpass_input = txl->volume_transmittance_accum; - break; - } case EEVEE_RENDER_PASS_SHADOW: { g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_VALUE; g_data->renderpass_input = txl->shadow_accum; break; } case EEVEE_RENDER_PASS_DIFFUSE_COLOR: { - g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_COLOR; + g_data->renderpass_postprocess = default_color_pass_type; g_data->renderpass_input = txl->diff_color_accum; break; } case EEVEE_RENDER_PASS_SPECULAR_COLOR: { - g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_COLOR; + g_data->renderpass_postprocess = default_color_pass_type; g_data->renderpass_input = txl->spec_color_accum; break; } case EEVEE_RENDER_PASS_ENVIRONMENT: { - g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_COLOR; + g_data->renderpass_postprocess = default_color_pass_type; g_data->renderpass_input = txl->env_accum; break; } case EEVEE_RENDER_PASS_EMIT: { - g_data->renderpass_postprocess = PASS_POST_ACCUMULATED_COLOR; + g_data->renderpass_postprocess = default_color_pass_type; g_data->renderpass_input = txl->emit_accum; break; } @@ -372,7 +397,8 @@ void EEVEE_renderpasses_output_accumulate(EEVEE_ViewLayerData *sldata, { EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; - eViewLayerEEVEEPassType render_pass = stl->g_data->render_passes; + EEVEE_PrivateData *g_data = stl->g_data; + eViewLayerEEVEEPassType render_pass = g_data->render_passes; if (!post_effect) { if ((render_pass & EEVEE_RENDER_PASS_MIST) != 0) { @@ -387,8 +413,7 @@ void EEVEE_renderpasses_output_accumulate(EEVEE_ViewLayerData *sldata, if ((render_pass & EEVEE_RENDERPASSES_MATERIAL) != 0) { EEVEE_material_output_accumulate(sldata, vedata); } - if ((render_pass & - (EEVEE_RENDER_PASS_VOLUME_TRANSMITTANCE | EEVEE_RENDER_PASS_VOLUME_SCATTER)) != 0) { + if (eevee_renderpasses_volumetric_active(effects, g_data)) { EEVEE_volumes_output_accumulate(sldata, vedata); } if ((render_pass & EEVEE_RENDER_PASS_CRYPTOMATTE) != 0) { diff --git a/source/blender/draw/engines/eevee/shaders/cryptomatte_frag.glsl b/source/blender/draw/engines/eevee/shaders/cryptomatte_frag.glsl index 1e499dbf991..9426b8e4a7b 100644 --- a/source/blender/draw/engines/eevee/shaders/cryptomatte_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/cryptomatte_frag.glsl @@ -4,4 +4,4 @@ out vec4 fragColor; void main() { fragColor = cryptohash; -}
\ No newline at end of file +} diff --git a/source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl b/source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl index eb6ca4b9de8..0bbbe58c44a 100644 --- a/source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl @@ -11,6 +11,7 @@ #define PASS_POST_AO 6 #define PASS_POST_NORMAL 7 #define PASS_POST_TWO_LIGHT_BUFFERS 8 +#define PASS_POST_ACCUMULATED_TRANSMITTANCE_COLOR 9 uniform int postProcessType; uniform int currentSample; @@ -19,6 +20,7 @@ uniform sampler2D depthBuffer; uniform sampler2D inputBuffer; uniform sampler2D inputSecondLightBuffer; uniform sampler2D inputColorBuffer; +uniform sampler2D inputTransmittanceBuffer; out vec4 fragColor; @@ -99,6 +101,11 @@ void main() vec4 accumulated_color = texelFetch(inputBuffer, texel, 0); color = (accumulated_color / currentSample); } + else if (postProcessType == PASS_POST_ACCUMULATED_TRANSMITTANCE_COLOR) { + vec3 accumulated_color = texelFetch(inputBuffer, texel, 0).rgb; + vec3 transmittance = texelFetch(inputTransmittanceBuffer, texel, 0).rgb; + color.rgb = (accumulated_color / currentSample) * (transmittance / currentSample); + } else if (postProcessType == PASS_POST_ACCUMULATED_LIGHT) { vec3 accumulated_light = texelFetch(inputBuffer, texel, 0).rgb; vec3 accumulated_color = texelFetch(inputColorBuffer, texel, 0).rgb; diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c index 388deec07bf..519b015a6ad 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.c +++ b/source/blender/draw/engines/gpencil/gpencil_engine.c @@ -252,7 +252,7 @@ void GPENCIL_cache_init(void *ved) pd->do_fast_drawing = false; pd->obact = draw_ctx->obact; - if (pd->obact && pd->obact->type == OB_GPENCIL) { + if (pd->obact && pd->obact->type == OB_GPENCIL && !(pd->draw_depth_only)) { /* Check if active object has a temp stroke data. */ bGPdata *gpd = (bGPdata *)pd->obact->data; if (gpd->runtime.sbuffer_used > 0) { diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h index 04128dc157e..d0bd56b42dd 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.h +++ b/source/blender/draw/engines/gpencil/gpencil_engine.h @@ -39,10 +39,7 @@ extern DrawEngineType draw_engine_gpencil_type; struct GPENCIL_Data; struct GPENCIL_StorageList; struct GPUBatch; -struct GPUVertBuf; -struct GPUVertFormat; struct GpencilBatchCache; -struct MaterialGPencilStyle; struct Object; struct RenderEngine; struct RenderLayer; diff --git a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c index d01aaaed8b0..cb65fbd6ae7 100644 --- a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c +++ b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c @@ -95,7 +95,7 @@ static DRWShadingGroup *gpencil_vfx_pass_create(const char *name, static void gpencil_vfx_blur(BlurShaderFxData *fx, Object *ob, gpIterVfxData *iter) { - if (fx->radius[0] == 0.0f && fx->radius[1] == 0.0f) { + if ((fx->samples == 0.0f) || (fx->radius[0] == 0.0f && fx->radius[1] == 0.0f)) { return; } diff --git a/source/blender/draw/engines/image/image_private.h b/source/blender/draw/engines/image/image_private.h index d5821cc5d70..76a94e68da1 100644 --- a/source/blender/draw/engines/image/image_private.h +++ b/source/blender/draw/engines/image/image_private.h @@ -25,11 +25,9 @@ extern "C" { #endif /* Forward declarations */ -struct GPUBatch; struct GPUTexture; struct ImBuf; struct Image; -struct rcti; /* *********** LISTS *********** */ diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_verts_frag.glsl b/source/blender/draw/engines/overlay/shaders/edit_uv_verts_frag.glsl index 1d936e4e072..ea2715a3c32 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_uv_verts_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/edit_uv_verts_frag.glsl @@ -1,6 +1,5 @@ -uniform vec4 outlineColor; - +in vec4 outlineColor; in vec4 radii; in vec4 fillColor; out vec4 fragColor; diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_verts_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_uv_verts_vert.glsl index 9e9df82a77d..cb70a3b433c 100644 --- a/source/blender/draw/engines/overlay/shaders/edit_uv_verts_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/edit_uv_verts_vert.glsl @@ -26,7 +26,7 @@ void main() /* Move selected vertices to the top * Vertices are between 0.0 and 0.2, Edges between 0.2 and 0.4 * actual pixels are at 0.75, 1.0 is used for the background. */ - float depth = is_selected ? 0.05 : 0.15; + float depth = is_selected ? (is_pinned ? 0.05 : 0.10) : 0.15; gl_Position = vec4(point_world_to_ndc(world_pos).xy, depth, 1.0); gl_PointSize = pointSize; diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index fbe71900915..4df2ba1e913 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -64,7 +64,6 @@ #include "DEG_depsgraph.h" struct GPUBatch; -struct GPUFrameBuffer; struct GPUMaterial; struct GPUShader; struct GPUTexture; diff --git a/source/blender/draw/intern/draw_cache_impl_particles.c b/source/blender/draw/intern/draw_cache_impl_particles.c index 75685c7e2f0..a9febcedbf9 100644 --- a/source/blender/draw/intern/draw_cache_impl_particles.c +++ b/source/blender/draw/intern/draw_cache_impl_particles.c @@ -38,6 +38,7 @@ #include "DNA_modifier_types.h" #include "DNA_particle_types.h" +#include "BKE_customdata.h" #include "BKE_mesh.h" #include "BKE_particle.h" #include "BKE_pointcache.h" diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h index 23dd47d4ab5..a059ac32311 100644 --- a/source/blender/draw/intern/draw_common.h +++ b/source/blender/draw/intern/draw_common.h @@ -22,10 +22,8 @@ #pragma once -struct DRWPass; struct DRWShadingGroup; struct FluidModifierData; -struct GPUMaterial; struct ModifierData; struct Object; struct ParticleSystem; diff --git a/source/blender/draw/intern/draw_instance_data.c b/source/blender/draw/intern/draw_instance_data.c index f1598ea2fff..ba03cee8149 100644 --- a/source/blender/draw/intern/draw_instance_data.c +++ b/source/blender/draw/intern/draw_instance_data.c @@ -669,10 +669,14 @@ static void drw_uniform_attribute_lookup(GPUUniformAttr *attr, DupliObject *dupli_source, float r_data[4]) { - char idprop_name[sizeof(attr->name) + 4]; - copy_v4_fl(r_data, 0); - sprintf(idprop_name, "[\"%s\"]", attr->name); + + char idprop_name[(sizeof(attr->name) * 2) + 4]; + { + char attr_name_esc[sizeof(attr->name) * 2]; + BLI_str_escape(attr_name_esc, attr->name, sizeof(attr_name_esc)); + SNPRINTF(idprop_name, "[\"%s\"]", attr_name_esc); + } /* If requesting instance data, check the parent particle system and object. */ if (attr->use_dupli) { diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 988975bd399..ffc565d0514 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -2073,7 +2073,6 @@ void DRW_draw_render_loop_2d_ex(struct Depsgraph *depsgraph, * for the image editor this is when showing UV's.*/ const bool do_populate_loop = (DST.draw_ctx.space_data->spacetype == SPACE_IMAGE); const bool do_annotations = drw_draw_show_annotation(); - const bool do_region_callbacks = (DST.draw_ctx.space_data->spacetype != SPACE_IMAGE); const bool do_draw_gizmos = (DST.draw_ctx.space_data->spacetype != SPACE_IMAGE); /* Get list of enabled engines */ @@ -2125,7 +2124,7 @@ void DRW_draw_render_loop_2d_ex(struct Depsgraph *depsgraph, /* Start Drawing */ DRW_state_reset(); - if (do_region_callbacks && DST.draw_ctx.evil_C) { + if (DST.draw_ctx.evil_C) { ED_region_draw_cb_draw(DST.draw_ctx.evil_C, DST.draw_ctx.region, REGION_DRAW_PRE_VIEW); } @@ -2147,10 +2146,8 @@ void DRW_draw_render_loop_2d_ex(struct Depsgraph *depsgraph, if (do_annotations) { ED_annotation_draw_view2d(DST.draw_ctx.evil_C, true); } - if (do_region_callbacks) { - GPU_depth_test(GPU_DEPTH_NONE); - ED_region_draw_cb_draw(DST.draw_ctx.evil_C, DST.draw_ctx.region, REGION_DRAW_POST_VIEW); - } + GPU_depth_test(GPU_DEPTH_NONE); + ED_region_draw_cb_draw(DST.draw_ctx.evil_C, DST.draw_ctx.region, REGION_DRAW_POST_VIEW); GPU_matrix_pop_projection(); /* Callback can be nasty and do whatever they want with the state. * Don't trust them! */ diff --git a/source/blender/draw/tests/shaders_test.cc b/source/blender/draw/tests/shaders_test.cc index 6674e3eccc1..d365f76aabe 100644 --- a/source/blender/draw/tests/shaders_test.cc +++ b/source/blender/draw/tests/shaders_test.cc @@ -332,8 +332,8 @@ TEST_F(DrawTest, eevee_glsl_shaders_static) EXPECT_NE(EEVEE_shaders_probe_grid_fill_sh_get(), nullptr); EXPECT_NE(EEVEE_shaders_probe_planar_downsample_sh_get(), nullptr); EXPECT_NE(EEVEE_shaders_renderpasses_post_process_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_cryptomatte_sh_get(index, false), nullptr); - EXPECT_NE(EEVEE_shaders_cryptomatte_sh_get(index, true), nullptr); + EXPECT_NE(EEVEE_shaders_cryptomatte_sh_get(false), nullptr); + EXPECT_NE(EEVEE_shaders_cryptomatte_sh_get(true), nullptr); EXPECT_NE(EEVEE_shaders_shadow_sh_get(), nullptr); EXPECT_NE(EEVEE_shaders_shadow_accum_sh_get(), nullptr); EXPECT_NE(EEVEE_shaders_subsurface_first_pass_sh_get(), nullptr); diff --git a/source/blender/editors/CMakeLists.txt b/source/blender/editors/CMakeLists.txt index 1f5dc73f732..a2ae350ce4b 100644 --- a/source/blender/editors/CMakeLists.txt +++ b/source/blender/editors/CMakeLists.txt @@ -22,6 +22,7 @@ if(WITH_BLENDER) add_subdirectory(animation) add_subdirectory(armature) + add_subdirectory(asset) add_subdirectory(curve) add_subdirectory(geometry) add_subdirectory(gizmo_library) diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index c70a86eab1d..6cb829d3a23 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -5353,7 +5353,7 @@ void ANIM_channel_draw_widgets(const bContext *C, "", ICON_NONE, offset, - ymid, + rect->ymin, SLIDER_WIDTH, channel_height); UI_but_func_set(but, achannel_setting_slider_nla_curve_cb, ale->id, ale->data); @@ -5411,7 +5411,7 @@ void ANIM_channel_draw_widgets(const bContext *C, "", icon, offset, - ymid, + rect->ymin, ICON_WIDTH, channel_height); } @@ -5437,7 +5437,7 @@ void ANIM_channel_draw_widgets(const bContext *C, "", icon, offset, - ymid, + rect->ymin, ICON_WIDTH, channel_height); } @@ -5457,7 +5457,7 @@ void ANIM_channel_draw_widgets(const bContext *C, "", ICON_NONE, offset, - ymid, + rect->ymin, width, channel_height); } @@ -5483,7 +5483,7 @@ void ANIM_channel_draw_widgets(const bContext *C, "", ICON_NONE, offset, - ymid, + rect->ymin, SLIDER_WIDTH, channel_height); diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index ba3796ad245..124992bed71 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -49,6 +49,7 @@ #include "BKE_gpencil.h" #include "BKE_lib_id.h" #include "BKE_mask.h" +#include "BKE_nla.h" #include "BKE_scene.h" #include "DEG_depsgraph.h" @@ -1063,18 +1064,27 @@ static void rearrange_animchannels_filter_visible(ListBase *anim_data_visible, eAnim_ChannelType type) { ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale, *ale_next; - int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); + eAnimFilter_Flags filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | + ANIMFILTER_LIST_CHANNELS); /* get all visible channels */ ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); /* now, only keep the ones that are of the types we are interested in */ - for (ale = anim_data.first; ale; ale = ale_next) { - ale_next = ale->next; - + LISTBASE_FOREACH_MUTABLE (bAnimListElem *, ale, &anim_data) { if (ale->type != type) { BLI_freelinkN(&anim_data, ale); + continue; + } + + if (type == ANIMTYPE_NLATRACK) { + NlaTrack *nlt = (NlaTrack *)ale->data; + + if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) { + /* No re-arrangement of non-local tracks of override data. */ + BLI_freelinkN(&anim_data, ale); + continue; + } } } @@ -1146,6 +1156,7 @@ static void rearrange_nla_channels(bAnimContext *ac, AnimData *adt, eRearrangeAn { AnimChanRearrangeFp rearrange_func; ListBase anim_data_visible = {NULL, NULL}; + const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ac->obact); /* hack: invert mode so that functions will work in right order */ mode *= -1; @@ -1156,6 +1167,29 @@ static void rearrange_nla_channels(bAnimContext *ac, AnimData *adt, eRearrangeAn return; } + /* In liboverride case, we need to extract non-local NLA tracks from current anim data before we + * can perform the move, and add then back afterwards. It's the only way to prevent them from + * being affected by the reordering. + * + * Note that both override apply code for NLA tracks collection, and NLA editing code, are + * responsible to ensure that non-local tracks always remain first in the list. */ + ListBase extracted_nonlocal_nla_tracks = {NULL, NULL}; + if (is_liboverride) { + NlaTrack *nla_track; + for (nla_track = adt->nla_tracks.first; nla_track != NULL; nla_track = nla_track->next) { + if (!BKE_nlatrack_is_nonlocal_in_liboverride(&ac->obact->id, nla_track)) { + break; + } + } + if (nla_track != NULL && nla_track->prev != NULL) { + extracted_nonlocal_nla_tracks.first = adt->nla_tracks.first; + extracted_nonlocal_nla_tracks.last = nla_track->prev; + adt->nla_tracks.first = nla_track; + nla_track->prev->next = NULL; + nla_track->prev = NULL; + } + } + /* Filter visible data. */ rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_NLATRACK); @@ -1163,6 +1197,14 @@ static void rearrange_nla_channels(bAnimContext *ac, AnimData *adt, eRearrangeAn rearrange_animchannel_islands( &adt->nla_tracks, rearrange_func, mode, ANIMTYPE_NLATRACK, &anim_data_visible); + /* Add back non-local NLA tracks at the begining of the animation data's list. */ + if (!BLI_listbase_is_empty(&extracted_nonlocal_nla_tracks)) { + BLI_assert(is_liboverride); + ((NlaTrack *)extracted_nonlocal_nla_tracks.last)->next = adt->nla_tracks.first; + ((NlaTrack *)adt->nla_tracks.first)->prev = extracted_nonlocal_nla_tracks.last; + adt->nla_tracks.first = extracted_nonlocal_nla_tracks.first; + } + /* free temp data */ BLI_freelistN(&anim_data_visible); } diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c index e552a321bca..17251587d3b 100644 --- a/source/blender/editors/animation/anim_deps.c +++ b/source/blender/editors/animation/anim_deps.c @@ -50,6 +50,7 @@ #include "RNA_access.h" #include "SEQ_sequencer.h" +#include "SEQ_utils.h" #include "ED_anim_api.h" @@ -212,15 +213,17 @@ static void animchan_sync_fcurve_scene(bAnimListElem *ale) return; } - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); /* get strip name, and check if this strip is selected */ char *seq_name = BLI_str_quoted_substrN(fcu->rna_path, "sequences_all["); - Sequence *seq = BKE_sequence_get_by_name(ed->seqbasep, seq_name, false); - if (seq_name) { - MEM_freeN(seq_name); + if (seq_name == NULL) { + return; } + Sequence *seq = SEQ_get_sequence_by_name(ed->seqbasep, seq_name, false); + MEM_freeN(seq_name); + if (seq == NULL) { return; } diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index 2e65fff69f1..f2022194ed5 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -101,6 +101,7 @@ #include "ED_markers.h" #include "SEQ_sequencer.h" +#include "SEQ_utils.h" #include "UI_resources.h" /* for TH_KEYFRAME_SCALE lookup */ @@ -225,7 +226,7 @@ static bool actedit_get_context(bAnimContext *ac, SpaceAction *saction) { /* TODO, other methods to get the mask */ #if 0 - Sequence *seq = BKE_sequencer_active_get(ac->scene); + Sequence *seq = SEQ_select_active_get(ac->scene); MovieClip *clip = ac->scene->clip; struct Mask *mask = seq ? seq->mask : NULL; #endif @@ -1063,13 +1064,12 @@ static bool skip_fcurve_selected_data(bDopeSheet *ads, FCurve *fcu, ID *owner_id /* only consider if F-Curve involves pose.bones */ if ((fcu->rna_path) && strstr(fcu->rna_path, "pose.bones")) { - bPoseChannel *pchan; - char *bone_name; /* get bone-name, and check if this bone is selected */ - bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones["); - pchan = BKE_pose_channel_find_name(ob->pose, bone_name); + bPoseChannel *pchan = NULL; + char *bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones["); if (bone_name) { + pchan = BKE_pose_channel_find_name(ob->pose, bone_name); MEM_freeN(bone_name); } @@ -1104,15 +1104,14 @@ static bool skip_fcurve_selected_data(bDopeSheet *ads, FCurve *fcu, ID *owner_id /* only consider if F-Curve involves sequence_editor.sequences */ if ((fcu->rna_path) && strstr(fcu->rna_path, "sequences_all")) { - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq = NULL; - char *seq_name; if (ed) { /* get strip name, and check if this strip is selected */ - seq_name = BLI_str_quoted_substrN(fcu->rna_path, "sequences_all["); - seq = BKE_sequence_get_by_name(ed->seqbasep, seq_name, false); + char *seq_name = BLI_str_quoted_substrN(fcu->rna_path, "sequences_all["); if (seq_name) { + seq = SEQ_get_sequence_by_name(ed->seqbasep, seq_name, false); MEM_freeN(seq_name); } } @@ -1130,13 +1129,12 @@ static bool skip_fcurve_selected_data(bDopeSheet *ads, FCurve *fcu, ID *owner_id /* check for selected nodes */ if ((fcu->rna_path) && strstr(fcu->rna_path, "nodes")) { - bNode *node; - char *node_name; + bNode *node = NULL; /* get strip name, and check if this strip is selected */ - node_name = BLI_str_quoted_substrN(fcu->rna_path, "nodes["); - node = nodeFindNodebyName(ntree, node_name); + char *node_name = BLI_str_quoted_substrN(fcu->rna_path, "nodes["); if (node_name) { + node = nodeFindNodebyName(ntree, node_name); MEM_freeN(node_name); } diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c index 72103d68b05..5992545bdbe 100644 --- a/source/blender/editors/animation/anim_ipo_utils.c +++ b/source/blender/editors/animation/anim_ipo_utils.c @@ -112,7 +112,8 @@ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu) char *constName = BLI_str_quoted_substrN(fcu->rna_path, "constraints["); /* assemble the string to display in the UI... */ - structname = BLI_sprintfN("%s : %s", pchanName, constName); + structname = BLI_sprintfN( + "%s : %s", pchanName ? pchanName : "", constName ? constName : ""); free_structname = 1; /* free the temp names */ diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c index 9e622aea6ab..a5514f6517e 100644 --- a/source/blender/editors/animation/anim_ops.c +++ b/source/blender/editors/animation/anim_ops.c @@ -56,6 +56,7 @@ #include "DEG_depsgraph_query.h" #include "SEQ_sequencer.h" +#include "SEQ_time.h" #include "anim_intern.h" @@ -93,7 +94,7 @@ static void change_frame_apply(bContext *C, wmOperator *op) if (do_snap) { if (CTX_wm_space_seq(C)) { - frame = BKE_sequencer_find_next_prev_edit(scene, frame, SEQ_SIDE_BOTH, true, false, false); + frame = SEQ_time_find_next_prev_edit(scene, frame, SEQ_SIDE_BOTH, true, false, false); } else { frame = BKE_scene_frame_snap_by_seconds(scene, 1.0, frame); @@ -503,7 +504,7 @@ static void ANIM_OT_previewrange_clear(wmOperatorType *ot) /* identifiers */ ot->name = "Clear Preview Range"; ot->idname = "ANIM_OT_previewrange_clear"; - ot->description = "Clear Preview Range"; + ot->description = "Clear preview range"; /* api callbacks */ ot->exec = previewrange_clear_exec; diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c index 08b02020f76..6ed9803dbd3 100644 --- a/source/blender/editors/animation/keyframes_general.c +++ b/source/blender/editors/animation/keyframes_general.c @@ -767,16 +767,15 @@ short copy_animedit_keys(bAnimContext *ac, ListBase *anim_data) * Storing the relevant information here helps avoiding crashes if we undo-repaste. */ if ((aci->id_type == ID_OB) && (((Object *)aci->id)->type == OB_ARMATURE) && aci->rna_path) { Object *ob = (Object *)aci->id; - bPoseChannel *pchan; - char *bone_name; - bone_name = BLI_str_quoted_substrN(aci->rna_path, "pose.bones["); - pchan = BKE_pose_channel_find_name(ob->pose, bone_name); - if (pchan) { - aci->is_bone = true; - } + char *bone_name = BLI_str_quoted_substrN(aci->rna_path, "pose.bones["); if (bone_name) { + bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, bone_name); MEM_freeN(bone_name); + + if (pchan) { + aci->is_bone = true; + } } } diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 09c33c48170..e8146ca960a 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -2236,20 +2236,18 @@ static int clear_anim_v3d_exec(bContext *C, wmOperator *UNUSED(op)) /* in pose mode, only delete the F-Curve if it belongs to a selected bone */ if (ob->mode & OB_MODE_POSE) { if ((fcu->rna_path) && strstr(fcu->rna_path, "pose.bones[")) { - bPoseChannel *pchan; - char *bone_name; /* get bone-name, and check if this bone is selected */ - bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones["); - pchan = BKE_pose_channel_find_name(ob->pose, bone_name); + char *bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones["); if (bone_name) { + bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, bone_name); MEM_freeN(bone_name); - } - /* delete if bone is selected*/ - if ((pchan) && (pchan->bone)) { - if (pchan->bone->flag & BONE_SELECTED) { - can_delete = true; + /* delete if bone is selected*/ + if ((pchan) && (pchan->bone)) { + if (pchan->bone->flag & BONE_SELECTED) { + can_delete = true; + } } } } @@ -2342,13 +2340,12 @@ static int delete_key_v3d_exec(bContext *C, wmOperator *op) * In object mode, we're dealing with the entire object. */ if ((ob->mode & OB_MODE_POSE) && strstr(fcu->rna_path, "pose.bones[\"")) { - bPoseChannel *pchan; - char *bone_name; + bPoseChannel *pchan = NULL; /* get bone-name, and check if this bone is selected */ - bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones["); - pchan = BKE_pose_channel_find_name(ob->pose, bone_name); + char *bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones["); if (bone_name) { + pchan = BKE_pose_channel_find_name(ob->pose, bone_name); MEM_freeN(bone_name); } diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c index b20d2738bda..f2cb00f67f0 100644 --- a/source/blender/editors/armature/armature_edit.c +++ b/source/blender/editors/armature/armature_edit.c @@ -1014,7 +1014,7 @@ void ARMATURE_OT_switch_direction(wmOperatorType *ot) /* identifiers */ ot->name = "Switch Direction"; ot->idname = "ARMATURE_OT_switch_direction"; - ot->description = "Change the direction that a chain of bones points in (head <-> tail swap)"; + ot->description = "Change the direction that a chain of bones points in (head and tail swap)"; /* api callbacks */ ot->exec = armature_switch_direction_exec; diff --git a/source/blender/editors/armature/editarmature_undo.c b/source/blender/editors/armature/editarmature_undo.c index c217b615db6..7c11c5e537e 100644 --- a/source/blender/editors/armature/editarmature_undo.c +++ b/source/blender/editors/armature/editarmature_undo.c @@ -26,7 +26,9 @@ #include "CLG_log.h" #include "DNA_armature_types.h" +#include "DNA_layer_types.h" #include "DNA_object_types.h" +#include "DNA_scene_types.h" #include "BLI_array_utils.h" #include "BLI_listbase.h" diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c index 731d0d10e0b..6a03207b3b0 100644 --- a/source/blender/editors/armature/pose_select.c +++ b/source/blender/editors/armature/pose_select.c @@ -1090,6 +1090,7 @@ static bool pose_select_same_keyingset(bContext *C, ReportList *reports, bool ex if (boneName) { bPoseChannel *pchan = BKE_pose_channel_find_name(pose, boneName); + MEM_freeN(boneName); if (pchan) { /* select if bone is visible and can be affected */ @@ -1098,9 +1099,6 @@ static bool pose_select_same_keyingset(bContext *C, ReportList *reports, bool ex changed = true; } } - - /* free temp memory */ - MEM_freeN(boneName); } } } diff --git a/source/blender/editors/asset/CMakeLists.txt b/source/blender/editors/asset/CMakeLists.txt new file mode 100644 index 00000000000..63a1761b264 --- /dev/null +++ b/source/blender/editors/asset/CMakeLists.txt @@ -0,0 +1,39 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# ***** END GPL LICENSE BLOCK ***** + +set(INC + ../include + ../../blenlib + ../../blenkernel + ../../makesdna + ../../makesrna + ../../windowmanager + ../../../../intern/guardedalloc +) + +set(INC_SYS +) + +set(SRC + asset_edit.c + asset_ops.c +) + +set(LIB +) + +blender_add_lib(bf_editor_asset "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/asset/asset_edit.c b/source/blender/editors/asset/asset_edit.c new file mode 100644 index 00000000000..5333c08c66a --- /dev/null +++ b/source/blender/editors/asset/asset_edit.c @@ -0,0 +1,69 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup edasset + */ + +#include "BKE_asset.h" +#include "BKE_context.h" +#include "BKE_idtype.h" +#include "BKE_lib_id.h" + +#include "DNA_ID.h" +#include "DNA_asset_types.h" + +#include "UI_interface_icons.h" + +#include "RNA_access.h" + +#include "ED_asset.h" + +bool ED_asset_mark_id(const bContext *C, ID *id) +{ + if (id->asset_data) { + return false; + } + if (!BKE_id_can_be_asset(id)) { + return false; + } + + id_fake_user_set(id); + + id->asset_data = BKE_asset_metadata_create(); + + UI_icon_render_id(C, NULL, id, true, true); + + return true; +} + +bool ED_asset_clear_id(ID *id) +{ + if (!id->asset_data) { + return false; + } + BKE_asset_metadata_free(&id->asset_data); + /* Don't clear fake user here, there's no guarantee that it was actually set by + * #ED_asset_mark_id(), it might have been something/someone else. */ + + return true; +} + +bool ED_asset_can_make_single_from_context(const bContext *C) +{ + /* Context needs a "id" pointer to be set for #ASSET_OT_mark()/#ASSET_OT_clear() to use. */ + return CTX_data_pointer_get_type_silent(C, "id", &RNA_ID).data != NULL; +} diff --git a/source/blender/editors/asset/asset_ops.c b/source/blender/editors/asset/asset_ops.c new file mode 100644 index 00000000000..929d49e19fa --- /dev/null +++ b/source/blender/editors/asset/asset_ops.c @@ -0,0 +1,238 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup edasset + */ + +#include <string.h> + +#include "BKE_asset.h" +#include "BKE_context.h" +#include "BKE_report.h" + +#include "BLI_listbase.h" +#include "BLI_string_utils.h" + +#include "DNA_asset_types.h" + +#include "ED_asset.h" + +#include "MEM_guardedalloc.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "WM_api.h" +#include "WM_types.h" + +/* -------------------------------------------------------------------- */ + +struct AssetMarkResultStats { + int tot_created; + int tot_already_asset; + ID *last_id; +}; + +/** + * Return the IDs to operate on as list of #CollectionPointerLink links. Needs freeing. + */ +static ListBase /* CollectionPointerLink */ asset_operation_get_ids_from_context(const bContext *C) +{ + ListBase list = {0}; + + PointerRNA idptr = CTX_data_pointer_get_type(C, "id", &RNA_ID); + + if (idptr.data) { + CollectionPointerLink *ctx_link = MEM_callocN(sizeof(*ctx_link), __func__); + ctx_link->ptr = idptr; + BLI_addtail(&list, ctx_link); + } + else { + CTX_data_selected_ids(C, &list); + } + + return list; +} + +static void asset_mark_for_idptr_list(const bContext *C, + const ListBase /* CollectionPointerLink */ *ids, + struct AssetMarkResultStats *r_stats) +{ + memset(r_stats, 0, sizeof(*r_stats)); + + LISTBASE_FOREACH (CollectionPointerLink *, ctx_id, ids) { + BLI_assert(RNA_struct_is_ID(ctx_id->ptr.type)); + + ID *id = ctx_id->ptr.data; + if (id->asset_data) { + r_stats->tot_already_asset++; + continue; + } + + if (ED_asset_mark_id(C, id)) { + r_stats->last_id = id; + r_stats->tot_created++; + } + } +} + +static bool asset_mark_results_report(const struct AssetMarkResultStats *stats, + ReportList *reports) +{ + /* User feedback on failure. */ + if ((stats->tot_created < 1) && (stats->tot_already_asset > 0)) { + BKE_report(reports, + RPT_ERROR, + "Selected data-blocks are already assets (or do not support use as assets)"); + return false; + } + if (stats->tot_created < 1) { + BKE_report(reports, + RPT_ERROR, + "No data-blocks to create assets for found (or do not support use as assets)"); + return false; + } + + /* User feedback on success. */ + if (stats->tot_created == 1) { + /* If only one data-block: Give more useful message by printing asset name. */ + BKE_reportf(reports, RPT_INFO, "Data-block '%s' is now an asset", stats->last_id->name + 2); + } + else { + BKE_reportf(reports, RPT_INFO, "%i data-blocks are now assets", stats->tot_created); + } + + return true; +} + +static int asset_mark_exec(bContext *C, wmOperator *op) +{ + ListBase ids = asset_operation_get_ids_from_context(C); + + struct AssetMarkResultStats stats; + asset_mark_for_idptr_list(C, &ids, &stats); + BLI_freelistN(&ids); + + if (!asset_mark_results_report(&stats, op->reports)) { + return OPERATOR_CANCELLED; + } + + WM_main_add_notifier(NC_ID | NA_EDITED, NULL); + WM_main_add_notifier(NC_ASSET | NA_ADDED, NULL); + + return OPERATOR_FINISHED; +} + +static void ASSET_OT_mark(wmOperatorType *ot) +{ + ot->name = "Mark Asset"; + ot->description = + "Enable easier reuse of selected data-blocks through the Asset Browser, with the help of " + "customizable metadata (like previews, descriptions and tags)"; + ot->idname = "ASSET_OT_mark"; + + ot->exec = asset_mark_exec; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/* -------------------------------------------------------------------- */ + +struct AssetClearResultStats { + int tot_removed; + ID *last_id; +}; + +static void asset_clear_from_idptr_list(const ListBase /* CollectionPointerLink */ *ids, + struct AssetClearResultStats *r_stats) +{ + memset(r_stats, 0, sizeof(*r_stats)); + + LISTBASE_FOREACH (CollectionPointerLink *, ctx_id, ids) { + BLI_assert(RNA_struct_is_ID(ctx_id->ptr.type)); + + ID *id = ctx_id->ptr.data; + if (!id->asset_data) { + continue; + } + + if (ED_asset_clear_id(id)) { + r_stats->tot_removed++; + r_stats->last_id = id; + } + } +} + +static bool asset_clear_result_report(const struct AssetClearResultStats *stats, + ReportList *reports) + +{ + if (stats->tot_removed < 1) { + BKE_report(reports, RPT_ERROR, "No asset data-blocks selected/focused"); + return false; + } + + if (stats->tot_removed == 1) { + /* If only one data-block: Give more useful message by printing asset name. */ + BKE_reportf( + reports, RPT_INFO, "Data-block '%s' is no asset anymore", stats->last_id->name + 2); + } + else { + BKE_reportf(reports, RPT_INFO, "%i data-blocks are no assets anymore", stats->tot_removed); + } + + return true; +} + +static int asset_clear_exec(bContext *C, wmOperator *op) +{ + ListBase ids = asset_operation_get_ids_from_context(C); + + struct AssetClearResultStats stats; + asset_clear_from_idptr_list(&ids, &stats); + BLI_freelistN(&ids); + + if (!asset_clear_result_report(&stats, op->reports)) { + return OPERATOR_CANCELLED; + } + + WM_main_add_notifier(NC_ID | NA_EDITED, NULL); + WM_main_add_notifier(NC_ASSET | NA_REMOVED, NULL); + + return OPERATOR_FINISHED; +} + +static void ASSET_OT_clear(wmOperatorType *ot) +{ + ot->name = "Clear Asset"; + ot->description = + "Delete all asset metadata and turn the selected asset data-blocks back into normal " + "data-blocks"; + ot->idname = "ASSET_OT_clear"; + + ot->exec = asset_clear_exec; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/* -------------------------------------------------------------------- */ + +void ED_operatortypes_asset(void) +{ + WM_operatortype_append(ASSET_OT_mark); + WM_operatortype_append(ASSET_OT_clear); +} diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index db472c9ffa7..2b627971286 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -3838,7 +3838,7 @@ void CURVE_OT_subdivide(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 1000, "Number of cuts", "", 1, 10); + prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 1000, "Number of Cuts", "", 1, 10); /* Avoid re-using last var because it can cause _very_ high poly meshes * and annoy users (or worse crash). */ RNA_def_property_flag(prop, PROP_SKIP_SAVE); diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt index 361c5d4048e..6ec7fbe80b6 100644 --- a/source/blender/editors/datafiles/CMakeLists.txt +++ b/source/blender/editors/datafiles/CMakeLists.txt @@ -657,6 +657,7 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES brush.sculpt.mask brush.sculpt.multiplane_scrape brush.sculpt.nudge + brush.sculpt.paint brush.sculpt.pinch brush.sculpt.pose brush.sculpt.rotate diff --git a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c index f7caf8e4c6a..8755dea51e1 100644 --- a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c +++ b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c @@ -50,7 +50,6 @@ #include "WM_api.h" #include "WM_types.h" -#include "wm.h" /* own includes */ #include "../gizmo_geometry.h" @@ -66,7 +65,13 @@ typedef struct SnapGizmo3D { /* We could have other snap contexts, for now only support 3D view. */ SnapObjectContext *snap_context_v3d; - int mval[2]; + + /* Copy of the parameters of the last event state in order to detect updates. */ + struct { + int x; + int y; + short shift, ctrl, alt, oskey; + } last_eventstate; #ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK wmKeyMap *keymap; @@ -77,6 +82,37 @@ typedef struct SnapGizmo3D { short snap_elem; } SnapGizmo3D; +/* Checks if the current event is different from the one captured in the last update. */ +static bool eventstate_has_changed(SnapGizmo3D *snap_gizmo, const wmWindowManager *wm) +{ + if (wm && wm->winactive) { + const wmEvent *event = wm->winactive->eventstate; + if ((event->x != snap_gizmo->last_eventstate.x) || + (event->y != snap_gizmo->last_eventstate.y) || + (event->ctrl != snap_gizmo->last_eventstate.ctrl) || + (event->shift != snap_gizmo->last_eventstate.shift) || + (event->alt != snap_gizmo->last_eventstate.alt) || + (event->oskey != snap_gizmo->last_eventstate.oskey)) { + return true; + } + } + return false; +} + +/* Copies the current eventstate. */ +static void eventstate_save(SnapGizmo3D *snap_gizmo, const wmWindowManager *wm) +{ + if (wm && wm->winactive) { + const wmEvent *event = wm->winactive->eventstate; + snap_gizmo->last_eventstate.x = event->x; + snap_gizmo->last_eventstate.y = event->y; + snap_gizmo->last_eventstate.ctrl = event->ctrl; + snap_gizmo->last_eventstate.shift = event->shift; + snap_gizmo->last_eventstate.alt = event->alt; + snap_gizmo->last_eventstate.oskey = event->oskey; + } +} + #ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK static bool invert_snap(SnapGizmo3D *snap_gizmo, const wmWindowManager *wm) { @@ -84,6 +120,15 @@ static bool invert_snap(SnapGizmo3D *snap_gizmo, const wmWindowManager *wm) return false; } + const wmEvent *event = wm->winactive->eventstate; + if ((event->ctrl == snap_gizmo->last_eventstate.ctrl) && + (event->shift == snap_gizmo->last_eventstate.shift) && + (event->alt == snap_gizmo->last_eventstate.alt) && + (event->oskey == snap_gizmo->last_eventstate.oskey)) { + /* Nothing has changed. */ + return snap_gizmo->invert_snap; + } + if (snap_gizmo->keymap == NULL) { /* Lazy initialization. */ snap_gizmo->keymap = WM_modalkeymap_find(wm->defaultconf, "Generic Gizmo Tweak Modal Map"); @@ -92,7 +137,6 @@ static bool invert_snap(SnapGizmo3D *snap_gizmo, const wmWindowManager *wm) const int snap_on = snap_gizmo->snap_on; wmKeyMap *keymap = WM_keymap_active(wm, snap_gizmo->keymap); - const wmEvent *event = wm->winactive->eventstate; for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) { if (kmi->flag & KMI_INACTIVE) { continue; @@ -250,12 +294,6 @@ short ED_gizmotypes_snap_3d_update(wmGizmo *gz, float r_nor[3]) { SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz; - Scene *scene = DEG_get_input_scene(depsgraph); - float co[3], no[3]; - short snap_elem = 0; - int snap_elem_index[3] = {-1, -1, -1}; - int index = -1; - if (snap_gizmo->use_snap_override != -1) { if (snap_gizmo->use_snap_override == false) { snap_gizmo->snap_elem = 0; @@ -265,7 +303,12 @@ short ED_gizmotypes_snap_3d_update(wmGizmo *gz, #ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK snap_gizmo->invert_snap = invert_snap(snap_gizmo, wm); +#endif + eventstate_save(snap_gizmo, wm); + Scene *scene = DEG_get_input_scene(depsgraph); + +#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK if (snap_gizmo->use_snap_override == -1) { const ToolSettings *ts = scene->toolsettings; if (snap_gizmo->invert_snap != !(ts->snap_flag & SCE_SNAP)) { @@ -273,10 +316,13 @@ short ED_gizmotypes_snap_3d_update(wmGizmo *gz, return 0; } } -#else - UNUSED_VARS(wm); #endif + float co[3], no[3]; + short snap_elem = 0; + int snap_elem_index[3] = {-1, -1, -1}; + int index = -1; + wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "snap_elements"); int snap_elements = RNA_property_enum_get(&gz_prop->ptr, gz_prop->prop); if (gz_prop->prop != snap_gizmo->prop_snap_force) { @@ -381,14 +427,17 @@ static void snap_gizmo_draw(const bContext *C, wmGizmo *gz) return; } - ARegion *region = CTX_wm_region(C); - RegionView3D *rv3d = region->regiondata; + wmWindowManager *wm = CTX_wm_manager(C); + if (eventstate_has_changed(snap_gizmo, wm)) { + /* The eventstate has changed but the snap has not been updated. + * This means that the current position is no longer valid. */ + snap_gizmo->snap_elem = 0; + return; + } - /* Ideally, we shouldn't assign values here. - * But `test_select` is not called during navigation. - * And `snap_elem` is not really useful in this case. */ - if ((rv3d->rflag & RV3D_NAVIGATING) || - (!(gz->state & WM_GIZMO_STATE_HIGHLIGHT) && !wm_gizmomap_modal_get(region->gizmo_map))) { + RegionView3D *rv3d = CTX_wm_region_data(C); + if (rv3d->rflag & RV3D_NAVIGATING) { + /* Don't draw the gizmo while navigating. It can be distracting. */ snap_gizmo->snap_elem = 0; return; } @@ -418,30 +467,17 @@ static void snap_gizmo_draw(const bContext *C, wmGizmo *gz) static int snap_gizmo_test_select(bContext *C, wmGizmo *gz, const int mval[2]) { SnapGizmo3D *snap_gizmo = (SnapGizmo3D *)gz; - -#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK wmWindowManager *wm = CTX_wm_manager(C); - const bool invert = invert_snap(snap_gizmo, wm); - if (snap_gizmo->invert_snap == invert && snap_gizmo->mval[0] == mval[0] && - snap_gizmo->mval[1] == mval[1]) { + if (!eventstate_has_changed(snap_gizmo, wm)) { /* Performance, do not update. */ return snap_gizmo->snap_elem ? 0 : -1; } - snap_gizmo->invert_snap = invert; -#else - if (snap_gizmo->mval[0] == mval[0] && snap_gizmo->mval[1] == mval[1]) { - /* Performance, do not update. */ - return snap_gizmo->snap_elem ? 0 : -1; - } -#endif - copy_v2_v2_int(snap_gizmo->mval, mval); - ARegion *region = CTX_wm_region(C); View3D *v3d = CTX_wm_view3d(C); const float mval_fl[2] = {UNPACK2(mval)}; short snap_elem = ED_gizmotypes_snap_3d_update( - gz, CTX_data_ensure_evaluated_depsgraph(C), region, v3d, NULL, mval_fl, NULL, NULL); + gz, CTX_data_ensure_evaluated_depsgraph(C), region, v3d, wm, mval_fl, NULL, NULL); if (snap_elem) { ED_region_tag_redraw_editor_overlays(region); diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c index 93767127cc7..4e2951c3571 100644 --- a/source/blender/editors/gpencil/drawgpencil.c +++ b/source/blender/editors/gpencil/drawgpencil.c @@ -41,6 +41,7 @@ #include "DNA_brush_types.h" #include "DNA_gpencil_types.h" +#include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" diff --git a/source/blender/editors/gpencil/gpencil_add_monkey.c b/source/blender/editors/gpencil/gpencil_add_monkey.c index 315b3c281da..65141442237 100644 --- a/source/blender/editors/gpencil/gpencil_add_monkey.c +++ b/source/blender/editors/gpencil/gpencil_add_monkey.c @@ -25,6 +25,7 @@ #include "BLI_utildefines.h" #include "DNA_gpencil_types.h" +#include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" diff --git a/source/blender/editors/gpencil/gpencil_add_stroke.c b/source/blender/editors/gpencil/gpencil_add_stroke.c index f26fd936d40..0c8cc621a3b 100644 --- a/source/blender/editors/gpencil/gpencil_add_stroke.c +++ b/source/blender/editors/gpencil/gpencil_add_stroke.c @@ -25,6 +25,7 @@ #include "BLI_utildefines.h" #include "DNA_gpencil_types.h" +#include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c index 63aa242275a..09b57029350 100644 --- a/source/blender/editors/gpencil/gpencil_convert.c +++ b/source/blender/editors/gpencil/gpencil_convert.c @@ -41,6 +41,7 @@ #include "DNA_collection_types.h" #include "DNA_curve_types.h" #include "DNA_gpencil_types.h" +#include "DNA_material_types.h" #include "DNA_node_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index 33a1469beab..aff109eb98e 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -42,6 +42,7 @@ #include "DNA_anim_types.h" #include "DNA_brush_types.h" #include "DNA_gpencil_types.h" +#include "DNA_material_types.h" #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" @@ -1330,19 +1331,24 @@ static int gpencil_merge_layer_exec(bContext *C, wmOperator *op) BLI_ghash_insert(gh_frames_dst, POINTER_FROM_INT(gpf_dst->framenum), gpf_dst); } - /* Read all frames from merge layer and add any missing in destination layer. */ + /* Read all frames from merge layer and add any missing in destination layer, + * copying all previous strokes to keep the image equals. + * Need to do it in a separated loop to avoid strokes accumulation. */ LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) { /* Try to find frame in destination layer hash table. */ bGPDframe *gpf_dst = BLI_ghash_lookup(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum)); if (!gpf_dst) { - gpf_dst = BKE_gpencil_frame_addnew(gpl_dst, gpf_src->framenum); - /* Duplicate strokes into destination frame. */ - if (gpf_dst) { - BKE_gpencil_frame_copy_strokes(gpf_src, gpf_dst); - } + gpf_dst = BKE_gpencil_layer_frame_get(gpl_dst, gpf_src->framenum, GP_GETFRAME_ADD_COPY); + BLI_ghash_insert(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum), gpf_dst); } - else { - /* Add to tail all strokes. */ + } + + /* Read all frames from merge layer and add strokes. */ + LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) { + /* Try to find frame in destination layer hash table. */ + bGPDframe *gpf_dst = BLI_ghash_lookup(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum)); + /* Add to tail all strokes. */ + if (gpf_dst) { BLI_movelisttolist(&gpf_dst->strokes, &gpf_src->strokes); } } diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 95c94f8cfed..36e383cf3c2 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -41,6 +41,7 @@ #include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" +#include "DNA_material_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index 93941ea3766..39968aac9fa 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -35,6 +35,7 @@ #include "DNA_brush_types.h" #include "DNA_gpencil_types.h" #include "DNA_image_types.h" +#include "DNA_material_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_windowmanager_types.h" diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c index 3617f20763e..1c967110198 100644 --- a/source/blender/editors/gpencil/gpencil_interpolate.c +++ b/source/blender/editors/gpencil/gpencil_interpolate.c @@ -283,8 +283,8 @@ static void gpencil_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) tgpil = MEM_callocN(sizeof(tGPDinterpolate_layer), "GPencil Interpolate Layer"); tgpil->gpl = gpl; - tgpil->prevFrame = gpl->actframe; - tgpil->nextFrame = gpl->actframe->next; + tgpil->prevFrame = BKE_gpencil_frame_duplicate(gpl->actframe); + tgpil->nextFrame = BKE_gpencil_frame_duplicate(gpl->actframe->next); BLI_addtail(&tgpi->ilayers, tgpil); @@ -326,24 +326,25 @@ static void gpencil_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) valid = false; } - /* create new stroke */ - new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true); - if (valid) { /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */ if (gps_from->totpoints > gps_to->totpoints) { - new_stroke->points = MEM_recallocN(new_stroke->points, - sizeof(*new_stroke->points) * gps_to->totpoints); - if (new_stroke->dvert != NULL) { - new_stroke->dvert = MEM_recallocN(new_stroke->dvert, - sizeof(*new_stroke->dvert) * gps_to->totpoints); - } - new_stroke->totpoints = gps_to->totpoints; + BKE_gpencil_stroke_uniform_subdivide(gpd, gps_to, gps_from->totpoints, true); } - /* update points position */ + if (gps_to->totpoints > gps_from->totpoints) { + BKE_gpencil_stroke_uniform_subdivide(gpd, gps_from, gps_to->totpoints, true); + } + + /* Create new stroke. */ + new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true); + + /* Update points position. */ gpencil_interpolate_update_points(gps_from, gps_to, new_stroke, tgpil->factor); } else { + /* Create new stroke. */ + new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true); + /* need an empty stroke to keep index correct for lookup, but resize to smallest size */ new_stroke->totpoints = 0; new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points)); @@ -443,12 +444,16 @@ static void gpencil_interpolate_exit(bContext *C, wmOperator *op) /* finally, free memory used by temp data */ LISTBASE_FOREACH (tGPDinterpolate_layer *, tgpil, &tgpi->ilayers) { + BKE_gpencil_free_strokes(tgpil->prevFrame); + BKE_gpencil_free_strokes(tgpil->nextFrame); BKE_gpencil_free_strokes(tgpil->interFrame); - MEM_freeN(tgpil->interFrame); + MEM_SAFE_FREE(tgpil->prevFrame); + MEM_SAFE_FREE(tgpil->nextFrame); + MEM_SAFE_FREE(tgpil->interFrame); } BLI_freelistN(&tgpi->ilayers); - MEM_freeN(tgpi); + MEM_SAFE_FREE(tgpi); } DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); @@ -478,14 +483,15 @@ static bool gpencil_interpolate_set_init_values(bContext *C, wmOperator *op, tGP /* set interpolation weight */ tgpi->shift = RNA_float_get(op->ptr, "shift"); - /* set layers */ - gpencil_interpolate_set_points(C, tgpi); /* Untag strokes to be sure nothing is pending due any canceled process. */ LISTBASE_FOREACH (bGPDlayer *, gpl, &tgpi->gpd->layers) { gpencil_interpolate_untag_strokes(gpl); } + /* Set layers */ + gpencil_interpolate_set_points(C, tgpi); + return 1; } @@ -992,8 +998,8 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) } /* store extremes */ - prevFrame = gpl->actframe; - nextFrame = gpl->actframe->next; + prevFrame = BKE_gpencil_frame_duplicate(gpl->actframe); + nextFrame = BKE_gpencil_frame_duplicate(gpl->actframe->next); /* Loop over intermediary frames and create the interpolation */ for (cframe = prevFrame->framenum + step; cframe < nextFrame->framenum; cframe += step) { @@ -1049,28 +1055,17 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) interFrame->key_type = BEZT_KEYTYPE_BREAKDOWN; } - /* create new stroke */ - bGPDstroke *new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true); - /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */ if (gps_from->totpoints > gps_to->totpoints) { - /* free weights of removed points */ - if (new_stroke->dvert != NULL) { - BKE_defvert_array_free_elems(new_stroke->dvert + gps_to->totpoints, - gps_from->totpoints - gps_to->totpoints); - } - - new_stroke->points = MEM_recallocN(new_stroke->points, - sizeof(*new_stroke->points) * gps_to->totpoints); - - if (new_stroke->dvert != NULL) { - new_stroke->dvert = MEM_recallocN(new_stroke->dvert, - sizeof(*new_stroke->dvert) * gps_to->totpoints); - } - - new_stroke->totpoints = gps_to->totpoints; + BKE_gpencil_stroke_uniform_subdivide(gpd, gps_to, gps_from->totpoints, true); + } + if (gps_to->totpoints > gps_from->totpoints) { + BKE_gpencil_stroke_uniform_subdivide(gpd, gps_from, gps_to->totpoints, true); } + /* create new stroke */ + bGPDstroke *new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true); + /* update points position */ gpencil_interpolate_update_points(gps_from, gps_to, new_stroke, factor); @@ -1081,6 +1076,11 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) BLI_addtail(&interFrame->strokes, new_stroke); } } + + BKE_gpencil_free_strokes(prevFrame); + BKE_gpencil_free_strokes(nextFrame); + MEM_SAFE_FREE(prevFrame); + MEM_SAFE_FREE(nextFrame); } /* notifiers */ diff --git a/source/blender/editors/gpencil/gpencil_merge.c b/source/blender/editors/gpencil/gpencil_merge.c index 9f2bf3818a4..272dff56291 100644 --- a/source/blender/editors/gpencil/gpencil_merge.c +++ b/source/blender/editors/gpencil/gpencil_merge.c @@ -31,6 +31,7 @@ #include "BLI_math.h" #include "DNA_gpencil_types.h" +#include "DNA_material_types.h" #include "BKE_brush.h" #include "BKE_context.h" diff --git a/source/blender/editors/gpencil/gpencil_ops_versioning.c b/source/blender/editors/gpencil/gpencil_ops_versioning.c index 4721736489e..815bbbaa254 100644 --- a/source/blender/editors/gpencil/gpencil_ops_versioning.c +++ b/source/blender/editors/gpencil/gpencil_ops_versioning.c @@ -33,6 +33,7 @@ #include "BLI_math.h" #include "DNA_gpencil_types.h" +#include "DNA_material_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c index ed18c2eed5d..bb9dd8cac5d 100644 --- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c +++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c @@ -41,6 +41,7 @@ #include "BLT_translation.h" #include "DNA_gpencil_types.h" +#include "DNA_material_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c index 2c0b9534141..281ab8c5adc 100644 --- a/source/blender/editors/gpencil/gpencil_select.c +++ b/source/blender/editors/gpencil/gpencil_select.c @@ -36,6 +36,7 @@ #include "BLI_utildefines.h" #include "DNA_gpencil_types.h" +#include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index e8e25a55796..c3ac33063af 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -40,7 +40,9 @@ #include "PIL_time.h" #include "DNA_brush_types.h" +#include "DNA_collection_types.h" #include "DNA_gpencil_types.h" +#include "DNA_material_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" diff --git a/source/blender/editors/gpencil/gpencil_vertex_ops.c b/source/blender/editors/gpencil/gpencil_vertex_ops.c index c3fd8d10b64..b212872b607 100644 --- a/source/blender/editors/gpencil/gpencil_vertex_ops.c +++ b/source/blender/editors/gpencil/gpencil_vertex_ops.c @@ -32,6 +32,7 @@ #include "DNA_brush_types.h" #include "DNA_gpencil_types.h" +#include "DNA_material_types.h" #include "BKE_colortools.h" #include "BKE_context.h" @@ -236,7 +237,7 @@ void GPENCIL_OT_vertex_color_brightness_contrast(wmOperatorType *ot) PropertyRNA *prop; /* identifiers */ - ot->name = "Vertex Paint Bright/Contrast"; + ot->name = "Vertex Paint Brightness/Contrast"; ot->idname = "GPENCIL_OT_vertex_color_brightness_contrast"; ot->description = "Adjust vertex color brightness/contrast"; diff --git a/source/blender/editors/gpencil/gpencil_vertex_paint.c b/source/blender/editors/gpencil/gpencil_vertex_paint.c index a4dc677f0dc..3afff897734 100644 --- a/source/blender/editors/gpencil/gpencil_vertex_paint.c +++ b/source/blender/editors/gpencil/gpencil_vertex_paint.c @@ -31,6 +31,7 @@ #include "DNA_brush_types.h" #include "DNA_gpencil_types.h" +#include "DNA_material_types.h" #include "BKE_brush.h" #include "BKE_colortools.h" diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h index 3501acd4fdf..0c4576096fb 100644 --- a/source/blender/editors/include/ED_armature.h +++ b/source/blender/editors/include/ED_armature.h @@ -31,7 +31,6 @@ struct Base; struct Bone; struct Depsgraph; struct EditBone; -struct IDProperty; struct ListBase; struct Main; struct Mesh; diff --git a/source/blender/editors/include/ED_asset.h b/source/blender/editors/include/ED_asset.h new file mode 100644 index 00000000000..6fe50528cc5 --- /dev/null +++ b/source/blender/editors/include/ED_asset.h @@ -0,0 +1,39 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup editors + */ + +#ifndef __ED_ASSET_H__ +#define __ED_ASSET_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +bool ED_asset_mark_id(const struct bContext *C, struct ID *id); +bool ED_asset_clear_id(struct ID *id); + +bool ED_asset_can_make_single_from_context(const struct bContext *C); + +void ED_operatortypes_asset(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __ED_ASSET_H__ */ diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h index 84808416074..7b240e0569f 100644 --- a/source/blender/editors/include/ED_fileselect.h +++ b/source/blender/editors/include/ED_fileselect.h @@ -28,7 +28,9 @@ extern "C" { #endif struct ARegion; +struct FileAssetSelectParams; struct FileSelectParams; +struct FileDirEntry; struct Scene; struct ScrArea; struct SpaceFile; @@ -101,16 +103,16 @@ typedef struct FileSelection { struct View2D; struct rcti; -struct FileSelectParams *ED_fileselect_get_params(struct SpaceFile *sfile); +struct FileSelectParams *ED_fileselect_ensure_active_params(struct SpaceFile *sfile); +struct FileSelectParams *ED_fileselect_get_active_params(const struct SpaceFile *sfile); +struct FileSelectParams *ED_fileselect_get_file_params(const struct SpaceFile *sfile); +struct FileAssetSelectParams *ED_fileselect_get_asset_params(const struct SpaceFile *sfile); -short ED_fileselect_set_params(struct SpaceFile *sfile); void ED_fileselect_set_params_from_userdef(struct SpaceFile *sfile); void ED_fileselect_params_to_userdef(struct SpaceFile *sfile, const int temp_win_size[], const bool is_maximized); -void ED_fileselect_reset_params(struct SpaceFile *sfile); - void ED_fileselect_init_layout(struct SpaceFile *sfile, struct ARegion *region); FileLayout *ED_fileselect_get_layout(struct SpaceFile *sfile, struct ARegion *region); @@ -142,6 +144,8 @@ void ED_fileselect_exit(struct wmWindowManager *wm, struct Scene *owner_scene, struct SpaceFile *sfile); +bool ED_fileselect_is_asset_browser(const struct SpaceFile *sfile); + void ED_fileselect_window_params_get(const struct wmWindow *win, int win_size[2], bool *is_maximized); @@ -151,6 +155,7 @@ struct ScrArea *ED_fileselect_handler_area_find(const struct wmWindow *win, int ED_path_extension_type(const char *path); int ED_file_extension_icon(const char *path); +int ED_file_icon(const struct FileDirEntry *file); void ED_file_read_bookmarks(void); diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index be2f714dfe1..1b7caf27ecf 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -51,7 +51,6 @@ struct ScrArea; struct SnapObjectContext; struct ToolSettings; struct View3D; -struct ViewLayer; struct bContext; struct Material; diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h index c1d3a17b9b6..b139b0765a3 100644 --- a/source/blender/editors/include/ED_image.h +++ b/source/blender/editors/include/ED_image.h @@ -34,12 +34,10 @@ struct ARegion; struct ImBuf; struct Image; struct ImageUser; -struct LinkNodePair; struct Main; struct ReportList; struct Scene; struct SpaceImage; -struct ViewLayer; struct bContext; struct wmOperator; struct wmWindowManager; diff --git a/source/blender/editors/include/ED_info.h b/source/blender/editors/include/ED_info.h index e3ce494e09a..9ac6b6c1085 100644 --- a/source/blender/editors/include/ED_info.h +++ b/source/blender/editors/include/ED_info.h @@ -38,8 +38,12 @@ const char *ED_info_statistics_string(struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer); -void ED_info_draw_stats( - struct Main *bmain, Scene *scene, ViewLayer *view_layer, int x, int *y, int height); +void ED_info_draw_stats(struct Main *bmain, + struct Scene *scene, + struct ViewLayer *view_layer, + int x, + int *y, + int height); #ifdef __cplusplus } diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index 2e9b711c99a..f9358f62274 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -53,7 +53,6 @@ struct uiLayout; struct wmKeyConfig; struct wmOperator; struct wmOperatorType; -struct wmWindowManager; /* object_edit.c */ /* context.object */ diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index dc1c43c0337..20417634020 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -239,6 +239,7 @@ void ED_screen_restore_temp_type(struct bContext *C, ScrArea *area); ScrArea *ED_screen_full_newspace(struct bContext *C, ScrArea *area, int type); void ED_screen_full_prevspace(struct bContext *C, ScrArea *area); void ED_screen_full_restore(struct bContext *C, ScrArea *area); +ScrArea *ED_screen_state_maximized_create(struct bContext *C); struct ScrArea *ED_screen_state_toggle(struct bContext *C, struct wmWindow *win, struct ScrArea *area, diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h index 0ea86e006e0..ca3e351a052 100644 --- a/source/blender/editors/include/ED_transform.h +++ b/source/blender/editors/include/ED_transform.h @@ -32,7 +32,6 @@ extern "C" { struct Object; struct bContext; struct wmKeyConfig; -struct wmMsgBus; struct wmOperatorType; void ED_keymap_transform(struct wmKeyConfig *keyconf); @@ -108,7 +107,6 @@ bool calculateTransformCenter(struct bContext *C, struct Object; struct Scene; -struct wmGizmoGroup; struct wmGizmoGroupType; /* UNUSED */ diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h index ebaa32941f2..b7174964ef6 100644 --- a/source/blender/editors/include/ED_transform_snap_object_context.h +++ b/source/blender/editors/include/ED_transform_snap_object_context.h @@ -31,7 +31,6 @@ struct BMVert; struct ARegion; struct Depsgraph; struct ListBase; -struct Main; struct Object; struct Scene; struct View3D; diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h index 68ae3589064..1e87a940a7d 100644 --- a/source/blender/editors/include/ED_util.h +++ b/source/blender/editors/include/ED_util.h @@ -52,7 +52,10 @@ void ED_spacedata_id_remap(struct ScrArea *area, struct ID *old_id, struct ID *new_id); -void ED_OT_flush_edits(struct wmOperatorType *ot); +void ED_OT_lib_id_load_custom_preview(struct wmOperatorType *ot); +void ED_OT_lib_id_generate_preview(struct wmOperatorType *ot); + +void ED_operatortypes_edutils(void); /* ************** XXX OLD CRUFT WARNING ************* */ diff --git a/source/blender/editors/include/ED_util_imbuf.h b/source/blender/editors/include/ED_util_imbuf.h index d142d3d6425..4bbaa68e849 100644 --- a/source/blender/editors/include/ED_util_imbuf.h +++ b/source/blender/editors/include/ED_util_imbuf.h @@ -31,7 +31,6 @@ extern "C" { #endif struct ARegion; -struct Main; struct bContext; struct wmEvent; struct wmOperator; diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h index 2066d7da511..4de97411059 100644 --- a/source/blender/editors/include/ED_uvedit.h +++ b/source/blender/editors/include/ED_uvedit.h @@ -33,7 +33,6 @@ struct BMEditMesh; struct BMFace; struct BMLoop; struct BMesh; -struct Depsgraph; struct Image; struct ImageUser; struct Main; @@ -217,8 +216,10 @@ struct BMLoop *ED_uvedit_active_vert_loop_get(struct BMesh *bm); void ED_uvedit_active_edge_loop_set(struct BMesh *bm, struct BMLoop *l); struct BMLoop *ED_uvedit_active_edge_loop_get(struct BMesh *bm); -char ED_uvedit_select_mode_get(const Scene *scene); -void ED_uvedit_select_sync_flush(const ToolSettings *ts, struct BMEditMesh *em, const bool select); +char ED_uvedit_select_mode_get(const struct Scene *scene); +void ED_uvedit_select_sync_flush(const struct ToolSettings *ts, + struct BMEditMesh *em, + const bool select); /* uvedit_unwrap_ops.c */ void ED_uvedit_live_unwrap_begin(struct Scene *scene, struct Object *obedit); @@ -244,7 +245,7 @@ struct UVPackIsland_Params { uint use_seams : 1; uint correct_aspect : 1; }; -void ED_uvedit_pack_islands_multi(const Scene *scene, +void ED_uvedit_pack_islands_multi(const struct Scene *scene, Object **objects, const uint objects_len, const struct UVPackIsland_Params *params); diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 596533406c3..a4856845a65 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -41,8 +41,6 @@ struct Camera; struct CustomData_MeshMasks; struct Depsgraph; struct EditBone; -struct GPUOffScreen; -struct GPUViewport; struct ID; struct MVert; struct Main; @@ -55,7 +53,6 @@ struct RenderEngineType; struct Scene; struct ScrArea; struct View3D; -struct View3DShading; struct ViewContext; struct ViewLayer; struct bContext; @@ -64,8 +61,6 @@ struct bScreen; struct rctf; struct rcti; struct wmGizmo; -struct wmOperator; -struct wmOperatorType; struct wmWindow; struct wmWindowManager; @@ -141,6 +136,11 @@ void ED_view3d_to_object(const struct Depsgraph *depsgraph, const float quat[4], const float dist); +bool ED_view3d_camera_to_view_selected(struct Main *bmain, + struct Depsgraph *depsgraph, + const struct Scene *scene, + struct Object *camera_ob); + void ED_view3d_lastview_store(struct RegionView3D *rv3d); /* Depth buffer */ diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h index faf34573475..79311042274 100644 --- a/source/blender/editors/include/UI_icons.h +++ b/source/blender/editors/include/UI_icons.h @@ -920,6 +920,7 @@ DEF_ICON_COLOR(BRUSH_TEXMASK) DEF_ICON_COLOR(BRUSH_THUMB) DEF_ICON_COLOR(BRUSH_ROTATE) DEF_ICON_COLOR(BRUSH_VCOL_BOUNDARY) +DEF_ICON_COLOR(BRUSH_PAINT) /* grease pencil sculpt */ DEF_ICON_COLOR(GPBRUSH_SMOOTH) diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 005dbf0e381..2705dd27756 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -50,7 +50,6 @@ struct PointerRNA; struct PropertyRNA; struct ReportList; struct ResultBLF; -struct ScrArea; struct bContext; struct bContextStore; struct bNode; @@ -77,6 +76,7 @@ struct wmWindow; typedef struct uiBlock uiBlock; typedef struct uiBut uiBut; +typedef struct uiButExtraOpIcon uiButExtraOpIcon; typedef struct uiLayout uiLayout; typedef struct uiPopupBlockHandle uiPopupBlockHandle; @@ -103,14 +103,19 @@ typedef struct uiPopupBlockHandle uiPopupBlockHandle; #define UI_SCREEN_MARGIN 10 /** #uiBlock.emboss and #uiBut.emboss */ -enum { +typedef enum eUIEmbossType { UI_EMBOSS = 0, /* use widget style for drawing */ UI_EMBOSS_NONE = 1, /* Nothing, only icon and/or text */ UI_EMBOSS_PULLDOWN = 2, /* Pulldown menu style */ UI_EMBOSS_RADIAL = 3, /* Pie Menu */ + /** + * The same as #UI_EMBOSS_NONE, unless the the button has + * a coloring status like an animation state or red alert. + */ + UI_EMBOSS_NONE_OR_STATUS = 4, UI_EMBOSS_UNDEFINED = 255, /* For layout engine, use emboss from block. */ -}; +} eUIEmbossType; /* uiBlock->direction */ enum { @@ -666,7 +671,7 @@ bool UI_popup_block_name_exists(const struct bScreen *screen, const char *name); uiBlock *UI_block_begin(const struct bContext *C, struct ARegion *region, const char *name, - char emboss); + eUIEmbossType emboss); void UI_block_end_ex(const struct bContext *C, uiBlock *block, const int xy[2], int r_xy[2]); void UI_block_end(const struct bContext *C, uiBlock *block); void UI_block_draw(const struct bContext *C, struct uiBlock *block); @@ -680,7 +685,7 @@ enum { }; void UI_block_theme_style_set(uiBlock *block, char theme_style); char UI_block_emboss_get(uiBlock *block); -void UI_block_emboss_set(uiBlock *block, char emboss); +void UI_block_emboss_set(uiBlock *block, eUIEmbossType emboss); bool UI_block_is_search_only(const uiBlock *block); void UI_block_set_search_only(uiBlock *block, bool search_only); @@ -727,6 +732,13 @@ void UI_block_translate(uiBlock *block, int x, int y); int UI_but_return_value_get(uiBut *but); void UI_but_drag_set_id(uiBut *but, struct ID *id); +void UI_but_drag_set_asset(uiBut *but, + const char *name, + const char *path, + int id_type, + int icon, + struct ImBuf *imb, + float scale); void UI_but_drag_set_rna(uiBut *but, struct PointerRNA *ptr); void UI_but_drag_set_path(uiBut *but, const char *path, const bool use_free); void UI_but_drag_set_name(uiBut *but, const char *name); @@ -1375,13 +1387,16 @@ typedef struct uiStringInfo { /* Note: Expects pointers to uiStringInfo structs as parameters. * Will fill them with translated strings, when possible. * Strings in uiStringInfo must be MEM_freeN'ed by caller. */ -void UI_but_string_info_get(struct bContext *C, uiBut *but, ...) ATTR_SENTINEL(0); +void UI_but_string_info_get(struct bContext *C, uiBut *but, uiButExtraOpIcon *extra_icon, ...) + ATTR_SENTINEL(0); /* Edit i18n stuff. */ /* Name of the main py op from i18n addon. */ #define EDTSRC_I18N_OP_NAME "UI_OT_edittranslation" /** + * TODO This is old stuff, only used by templateID. Should be cleaned up. + * * Special Buttons * * Buttons with a more specific purpose: @@ -1399,14 +1414,16 @@ enum { UI_ID_ALONE = 1 << 4, UI_ID_OPEN = 1 << 3, UI_ID_DELETE = 1 << 5, - UI_ID_LOCAL = 1 << 6, - UI_ID_AUTO_NAME = 1 << 7, - UI_ID_FAKE_USER = 1 << 8, + UI_ID_MAKE_LOCAL = 1 << 6, + UI_ID_LIB_OVERRIDE_ADD = 1 << 7, + UI_ID_AUTO_NAME = 1 << 8, UI_ID_PIN = 1 << 9, UI_ID_PREVIEWS = 1 << 10, - UI_ID_OVERRIDE = 1 << 11, + UI_ID_LIB_OVERRIDE_REMOVE = 1 << 11, + UI_ID_LIB_OVERRIDE_RESET = 1 << 12, UI_ID_FULL = UI_ID_RENAME | UI_ID_BROWSE | UI_ID_ADD_NEW | UI_ID_OPEN | UI_ID_ALONE | - UI_ID_DELETE | UI_ID_LOCAL, + UI_ID_DELETE | UI_ID_MAKE_LOCAL | UI_ID_LIB_OVERRIDE_ADD | + UI_ID_LIB_OVERRIDE_REMOVE | UI_ID_LIB_OVERRIDE_RESET, }; /** @@ -1652,10 +1669,12 @@ void UI_but_func_hold_set(uiBut *but, uiButHandleHoldFunc func, void *argN); void UI_but_func_pushed_state_set(uiBut *but, uiButPushedStateFunc func, void *arg); -PointerRNA *UI_but_extra_operator_icon_add(uiBut *but, - const char *opname, - short opcontext, - int icon); +struct uiButExtraOpIcon *UI_but_extra_operator_icon_add(uiBut *but, + const char *opname, + short opcontext, + int icon); +struct wmOperatorType *UI_but_extra_operator_icon_optype_get(struct uiButExtraOpIcon *extra_icon); +PointerRNA *UI_but_extra_operator_icon_opptr_get(struct uiButExtraOpIcon *extra_icon); /* Autocomplete * @@ -1879,6 +1898,7 @@ uiBlock *uiLayoutGetBlock(uiLayout *layout); void uiLayoutSetFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv); void uiLayoutSetContextPointer(uiLayout *layout, const char *name, struct PointerRNA *ptr); +struct bContextStore *uiLayoutGetContextStore(uiLayout *layout); void uiLayoutContextCopy(uiLayout *layout, struct bContextStore *context); struct wmOperatorType *UI_but_operatortype_get_from_enum_menu(struct uiBut *but, PropertyRNA **r_prop); @@ -1903,7 +1923,7 @@ void uiLayoutSetScaleX(uiLayout *layout, float scale); void uiLayoutSetScaleY(uiLayout *layout, float scale); void uiLayoutSetUnitsX(uiLayout *layout, float unit); void uiLayoutSetUnitsY(uiLayout *layout, float unit); -void uiLayoutSetEmboss(uiLayout *layout, char emboss); +void uiLayoutSetEmboss(uiLayout *layout, eUIEmbossType emboss); void uiLayoutSetPropSep(uiLayout *layout, bool is_sep); void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep); int uiLayoutGetLocalDir(const uiLayout *layout); @@ -1922,7 +1942,7 @@ float uiLayoutGetScaleX(uiLayout *layout); float uiLayoutGetScaleY(uiLayout *layout); float uiLayoutGetUnitsX(uiLayout *layout); float uiLayoutGetUnitsY(uiLayout *layout); -int uiLayoutGetEmboss(uiLayout *layout); +eUIEmbossType uiLayoutGetEmboss(uiLayout *layout); bool uiLayoutGetPropSep(uiLayout *layout); bool uiLayoutGetPropDecorate(uiLayout *layout); @@ -1956,6 +1976,7 @@ void uiTemplateID(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *newop, + const char *duplicateop, const char *openop, const char *unlinkop, int filter, @@ -2560,6 +2581,11 @@ struct ARegion *UI_tooltip_create_from_button(struct bContext *C, struct ARegion *butregion, uiBut *but, bool is_label); +struct ARegion *UI_tooltip_create_from_button_or_extra_icon(struct bContext *C, + struct ARegion *butregion, + uiBut *but, + uiButExtraOpIcon *extra_icon, + bool is_label); struct ARegion *UI_tooltip_create_from_gizmo(struct bContext *C, struct wmGizmo *gz); void UI_tooltip_free(struct bContext *C, struct bScreen *screen, struct ARegion *region); diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 4a02c6b6e88..7713efd1c78 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -1167,16 +1167,21 @@ void ui_but_add_shortcut(uiBut *but, const char *shortcut_str, const bool do_str * \{ */ static bool ui_but_event_operator_string_from_operator(const bContext *C, - uiBut *but, + wmOperatorCallParams *op_call_params, char *buf, const size_t buf_len) { - BLI_assert(but->optype != NULL); + BLI_assert(op_call_params->optype != NULL); bool found = false; - IDProperty *prop = (but->opptr) ? but->opptr->data : NULL; - - if (WM_key_event_operator_string( - C, but->optype->idname, but->opcontext, prop, true, buf, buf_len)) { + IDProperty *prop = (op_call_params->opptr) ? op_call_params->opptr->data : NULL; + + if (WM_key_event_operator_string(C, + op_call_params->optype->idname, + op_call_params->opcontext, + prop, + true, + buf, + buf_len)) { found = true; } return found; @@ -1253,15 +1258,22 @@ static bool ui_but_event_operator_string_from_panel(const bContext *C, return found; } -static bool ui_but_event_operator_string(const bContext *C, - uiBut *but, - char *buf, - const size_t buf_len) +static bool ui_but_event_operator_string( + const bContext *C, uiBut *but, uiButExtraOpIcon *extra_icon, char *buf, const size_t buf_len) { bool found = false; + wmOperatorType *extra_icon_optype = UI_but_extra_operator_icon_optype_get(extra_icon); - if (but->optype != NULL) { - found = ui_but_event_operator_string_from_operator(C, but, buf, buf_len); + if (extra_icon_optype) { + found = ui_but_event_operator_string_from_operator(C, extra_icon->optype_params, buf, buf_len); + } + else if (but->optype != NULL) { + found = ui_but_event_operator_string_from_operator( + C, + &(wmOperatorCallParams){ + .optype = but->optype, .opptr = but->opptr, .opcontext = but->opcontext}, + buf, + buf_len); } else if (UI_but_menutype_get(but) != NULL) { found = ui_but_event_operator_string_from_menu(C, but, buf, buf_len); @@ -1564,7 +1576,7 @@ static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block) continue; } - if (ui_but_event_operator_string(C, but, buf, sizeof(buf))) { + if (ui_but_event_operator_string(C, but, NULL, buf, sizeof(buf))) { ui_but_add_shortcut(but, buf, false); } else if (ui_but_event_property_operator_string(C, but, buf, sizeof(buf))) { @@ -1605,12 +1617,12 @@ typedef enum PredefinedExtraOpIconType { PREDEFINED_EXTRA_OP_ICON_EYEDROPPER, } PredefinedExtraOpIconType; -static PointerRNA *ui_but_extra_operator_icon_add_ptr(uiBut *but, - wmOperatorType *optype, - short opcontext, - int icon) +static uiButExtraOpIcon *ui_but_extra_operator_icon_add_ptr(uiBut *but, + wmOperatorType *optype, + short opcontext, + int icon) { - uiButExtraOpIcon *extra_op_icon = MEM_mallocN(sizeof(*extra_op_icon), __func__); + uiButExtraOpIcon *extra_op_icon = MEM_callocN(sizeof(*extra_op_icon), __func__); extra_op_icon->icon = (BIFIconID)icon; extra_op_icon->optype_params = MEM_callocN(sizeof(*extra_op_icon->optype_params), @@ -1625,13 +1637,15 @@ static PointerRNA *ui_but_extra_operator_icon_add_ptr(uiBut *but, BLI_addtail(&but->extra_op_icons, extra_op_icon); - return extra_op_icon->optype_params->opptr; + return extra_op_icon; } static void ui_but_extra_operator_icon_free(uiButExtraOpIcon *extra_icon) { - WM_operator_properties_free(extra_icon->optype_params->opptr); - MEM_freeN(extra_icon->optype_params->opptr); + if (extra_icon->optype_params->opptr) { + WM_operator_properties_free(extra_icon->optype_params->opptr); + MEM_freeN(extra_icon->optype_params->opptr); + } MEM_freeN(extra_icon->optype_params); MEM_freeN(extra_icon); } @@ -1644,18 +1658,25 @@ void ui_but_extra_operator_icons_free(uiBut *but) BLI_listbase_clear(&but->extra_op_icons); } -PointerRNA *UI_but_extra_operator_icon_add(uiBut *but, - const char *opname, - short opcontext, - int icon) +uiButExtraOpIcon *UI_but_extra_operator_icon_add(uiBut *but, + const char *opname, + short opcontext, + int icon) { wmOperatorType *optype = WM_operatortype_find(opname, false); - if (optype) { - return ui_but_extra_operator_icon_add_ptr(but, optype, opcontext, icon); - } + BLI_assert(optype); + return ui_but_extra_operator_icon_add_ptr(but, optype, opcontext, icon); +} - return NULL; +PointerRNA *UI_but_extra_operator_icon_opptr_get(uiButExtraOpIcon *extra_icon) +{ + return extra_icon->optype_params->opptr; +} + +wmOperatorType *UI_but_extra_operator_icon_optype_get(uiButExtraOpIcon *extra_icon) +{ + return extra_icon ? extra_icon->optype_params->optype : NULL; } static bool ui_but_icon_extra_is_visible_text_clear(const uiBut *but) @@ -3352,7 +3373,7 @@ static void ui_but_free(const bContext *C, uiBut *but) } if (but->dragpoin && (but->dragflag & UI_BUT_DRAGPOIN_FREE)) { - MEM_freeN(but->dragpoin); + WM_drag_data_free(but->dragtype, but->dragpoin); } ui_but_extra_operator_icons_free(but); @@ -3457,7 +3478,7 @@ void UI_block_region_set(uiBlock *block, ARegion *region) block->oldblock = oldblock; } -uiBlock *UI_block_begin(const bContext *C, ARegion *region, const char *name, char emboss) +uiBlock *UI_block_begin(const bContext *C, ARegion *region, const char *name, eUIEmbossType emboss) { wmWindow *window = CTX_wm_window(C); Scene *scene = CTX_data_scene(C); @@ -3508,7 +3529,7 @@ char UI_block_emboss_get(uiBlock *block) return block->emboss; } -void UI_block_emboss_set(uiBlock *block, char emboss) +void UI_block_emboss_set(uiBlock *block, eUIEmbossType emboss) { block->emboss = emboss; } @@ -4552,6 +4573,15 @@ static uiBut *ui_def_but_rna(uiBlock *block, UI_but_disable(but, info); } + if (proptype == PROP_POINTER) { + /* If the button shows an ID, automatically set it as focused in context so operators can + * access it.*/ + const PointerRNA pptr = RNA_property_pointer_get(ptr, prop); + if (pptr.data && RNA_struct_is_ID(pptr.type)) { + but->context = CTX_store_add(&block->contexts, "id", &pptr); + } + } + if (but->flag & UI_BUT_UNDO && (ui_but_is_rna_undo(but) == false)) { but->flag &= ~UI_BUT_UNDO; } @@ -6089,17 +6119,42 @@ void UI_but_drag_set_id(uiBut *but, ID *id) { but->dragtype = WM_DRAG_ID; if ((but->dragflag & UI_BUT_DRAGPOIN_FREE)) { - MEM_SAFE_FREE(but->dragpoin); + WM_drag_data_free(but->dragtype, but->dragpoin); but->dragflag &= ~UI_BUT_DRAGPOIN_FREE; } but->dragpoin = (void *)id; } +void UI_but_drag_set_asset(uiBut *but, + const char *name, + const char *path, + int id_type, + int icon, + struct ImBuf *imb, + float scale) +{ + wmDragAsset *asset_drag = MEM_mallocN(sizeof(*asset_drag), "wmDragAsset"); + + BLI_strncpy(asset_drag->name, name, sizeof(asset_drag->name)); + asset_drag->path = path; + asset_drag->id_type = id_type; + + but->dragtype = WM_DRAG_ASSET; + ui_def_but_icon(but, icon, 0); /* no flag UI_HAS_ICON, so icon doesn't draw in button */ + if ((but->dragflag & UI_BUT_DRAGPOIN_FREE)) { + WM_drag_data_free(but->dragtype, but->dragpoin); + } + but->dragpoin = asset_drag; + but->dragflag |= UI_BUT_DRAGPOIN_FREE; + but->imb = imb; + but->imb_scale = scale; +} + void UI_but_drag_set_rna(uiBut *but, PointerRNA *ptr) { but->dragtype = WM_DRAG_RNA; if ((but->dragflag & UI_BUT_DRAGPOIN_FREE)) { - MEM_SAFE_FREE(but->dragpoin); + WM_drag_data_free(but->dragtype, but->dragpoin); but->dragflag &= ~UI_BUT_DRAGPOIN_FREE; } but->dragpoin = (void *)ptr; @@ -6109,7 +6164,7 @@ void UI_but_drag_set_path(uiBut *but, const char *path, const bool use_free) { but->dragtype = WM_DRAG_PATH; if ((but->dragflag & UI_BUT_DRAGPOIN_FREE)) { - MEM_SAFE_FREE(but->dragpoin); + WM_drag_data_free(but->dragtype, but->dragpoin); but->dragflag &= ~UI_BUT_DRAGPOIN_FREE; } but->dragpoin = (void *)path; @@ -6122,7 +6177,7 @@ void UI_but_drag_set_name(uiBut *but, const char *name) { but->dragtype = WM_DRAG_NAME; if ((but->dragflag & UI_BUT_DRAGPOIN_FREE)) { - MEM_SAFE_FREE(but->dragpoin); + WM_drag_data_free(but->dragtype, but->dragpoin); but->dragflag &= ~UI_BUT_DRAGPOIN_FREE; } but->dragpoin = (void *)name; @@ -6140,7 +6195,7 @@ void UI_but_drag_set_image( but->dragtype = WM_DRAG_PATH; ui_def_but_icon(but, icon, 0); /* no flag UI_HAS_ICON, so icon doesn't draw in button */ if ((but->dragflag & UI_BUT_DRAGPOIN_FREE)) { - MEM_SAFE_FREE(but->dragpoin); + WM_drag_data_free(but->dragtype, but->dragpoin); but->dragflag &= ~UI_BUT_DRAGPOIN_FREE; } but->dragpoin = (void *)path; @@ -6784,7 +6839,7 @@ void UI_but_func_hold_set(uiBut *but, uiButHandleHoldFunc func, void *argN) but->hold_argN = argN; } -void UI_but_string_info_get(bContext *C, uiBut *but, ...) +void UI_but_string_info_get(bContext *C, uiBut *but, uiButExtraOpIcon *extra_icon, ...) { va_list args; uiStringInfo *si; @@ -6793,13 +6848,19 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...) int totitems; bool free_items = false; - va_start(args, but); + wmOperatorType *extra_icon_optype = UI_but_extra_operator_icon_optype_get(extra_icon); + wmOperatorType *optype = extra_icon ? extra_icon_optype : but->optype; + + /* Don't query RNA data when the extra-icon overrides the button. */ + PropertyRNA *rnaprop = extra_icon ? NULL : but->rnaprop; + + va_start(args, extra_icon); while ((si = (uiStringInfo *)va_arg(args, void *))) { uiStringInfoType type = si->type; char *tmp = NULL; if (type == BUT_GET_LABEL) { - if (but->str && but->str[0]) { + if (but->str && but->str[0] && !extra_icon) { const char *str_sep; size_t str_len; @@ -6829,16 +6890,16 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...) } if (type == BUT_GET_RNAPROP_IDENTIFIER) { - if (but->rnaprop) { - tmp = BLI_strdup(RNA_property_identifier(but->rnaprop)); + if (rnaprop) { + tmp = BLI_strdup(RNA_property_identifier(rnaprop)); } } else if (type == BUT_GET_RNASTRUCT_IDENTIFIER) { - if (but->rnaprop && but->rnapoin.data) { + if (rnaprop && but->rnapoin.data) { tmp = BLI_strdup(RNA_struct_identifier(but->rnapoin.type)); } - else if (but->optype) { - tmp = BLI_strdup(but->optype->idname); + else if (optype) { + tmp = BLI_strdup(optype->idname); } else if (ELEM(but->type, UI_BTYPE_MENU, UI_BTYPE_PULLDOWN)) { MenuType *mt = UI_but_menutype_get(but); @@ -6854,23 +6915,25 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...) } } else if (ELEM(type, BUT_GET_RNA_LABEL, BUT_GET_RNA_TIP)) { - if (but->rnaprop) { + if (rnaprop) { if (type == BUT_GET_RNA_LABEL) { - tmp = BLI_strdup(RNA_property_ui_name(but->rnaprop)); + tmp = BLI_strdup(RNA_property_ui_name(rnaprop)); } else { - const char *t = RNA_property_ui_description(but->rnaprop); + const char *t = RNA_property_ui_description(rnaprop); if (t && t[0]) { tmp = BLI_strdup(t); } } } - else if (but->optype) { + else if (optype) { + PointerRNA *opptr = extra_icon_optype ? UI_but_extra_operator_icon_opptr_get(extra_icon) : + but->opptr; if (type == BUT_GET_RNA_LABEL) { - tmp = BLI_strdup(WM_operatortype_name(but->optype, but->opptr)); + tmp = BLI_strdup(WM_operatortype_name(optype, opptr)); } else { - tmp = WM_operatortype_description(C, but->optype, but->opptr); + tmp = WM_operatortype_description(C, optype, opptr); } } else if (ELEM(but->type, UI_BTYPE_MENU, UI_BTYPE_PULLDOWN, UI_BTYPE_POPOVER)) { @@ -6922,11 +6985,11 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...) } else if (type == BUT_GET_RNA_LABEL_CONTEXT) { const char *_tmp = BLT_I18NCONTEXT_DEFAULT; - if (but->rnaprop) { - _tmp = RNA_property_translation_context(but->rnaprop); + if (rnaprop) { + _tmp = RNA_property_translation_context(rnaprop); } - else if (but->optype) { - _tmp = RNA_struct_translation_context(but->optype->srna); + else if (optype) { + _tmp = RNA_struct_translation_context(optype->srna); } else if (ELEM(but->type, UI_BTYPE_MENU, UI_BTYPE_PULLDOWN)) { MenuType *mt = UI_but_menutype_get(but); @@ -6945,16 +7008,16 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...) int value = 0; /* get the enum property... */ - if (but->rnaprop && RNA_property_type(but->rnaprop) == PROP_ENUM) { + if (rnaprop && RNA_property_type(rnaprop) == PROP_ENUM) { /* enum property */ ptr = &but->rnapoin; - prop = but->rnaprop; + prop = rnaprop; value = (ELEM(but->type, UI_BTYPE_ROW, UI_BTYPE_TAB)) ? (int)but->hardmax : (int)ui_but_value_get(but); } - else if (but->optype) { - PointerRNA *opptr = UI_but_operator_ptr_get(but); - wmOperatorType *ot = but->optype; + else if (optype) { + PointerRNA *opptr = extra_icon_optype ? UI_but_extra_operator_icon_opptr_get(extra_icon) : + UI_but_operator_ptr_get(but); /* so the context is passed to itemf functions */ WM_operator_properties_sanitize(opptr, false); @@ -6964,11 +7027,11 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...) * operator menus in the Anim Editors will show tooltips for the different * operations instead of the meaningless generic operator tooltip */ - if (ot->prop && RNA_property_type(ot->prop) == PROP_ENUM) { - if (RNA_struct_contains_property(opptr, ot->prop)) { + if (optype->prop && RNA_property_type(optype->prop) == PROP_ENUM) { + if (RNA_struct_contains_property(opptr, optype->prop)) { ptr = opptr; - prop = ot->prop; - value = RNA_property_enum_get(opptr, ot->prop); + prop = optype->prop; + value = RNA_property_enum_get(opptr, optype->prop); } } } @@ -7001,7 +7064,7 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...) else if (type == BUT_GET_OP_KEYMAP) { if (!ui_block_is_menu(but->block)) { char buf[128]; - if (ui_but_event_operator_string(C, but, buf, sizeof(buf))) { + if (ui_but_event_operator_string(C, but, extra_icon, buf, sizeof(buf))) { tmp = BLI_strdup(buf); } } diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c index 39b405a02b8..fd3b00eec31 100644 --- a/source/blender/editors/interface/interface_context_menu.c +++ b/source/blender/editors/interface/interface_context_menu.c @@ -38,6 +38,7 @@ #include "BKE_idprop.h" #include "BKE_screen.h" +#include "ED_asset.h" #include "ED_keyframing.h" #include "ED_screen.h" @@ -503,17 +504,23 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) uiPopupMenu *pup; uiLayout *layout; + bContextStore *previous_ctx = CTX_store_get(C); { uiStringInfo label = {BUT_GET_LABEL, NULL}; /* highly unlikely getting the label ever fails */ - UI_but_string_info_get(C, but, &label, NULL); + UI_but_string_info_get(C, but, NULL, &label, NULL); pup = UI_popup_menu_begin(C, label.strinfo ? label.strinfo : "", ICON_NONE); layout = UI_popup_menu_layout(pup); if (label.strinfo) { MEM_freeN(label.strinfo); } + + if (but->context) { + uiLayoutContextCopy(layout, but->context); + CTX_store_set(C, uiLayoutGetContextStore(layout)); + } uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT); } @@ -946,6 +953,22 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) } } + /* If the button reprents an id, it can set the "id" context pointer. */ + if (ED_asset_can_make_single_from_context(C)) { + ID *id = CTX_data_pointer_get_type(C, "id", &RNA_ID).data; + + /* Gray out items depending on if data-block is an asset. Preferably this could be done via + * operator poll, but that doesn't work since the operator also works with "selected_ids", + * which isn't cheap to check. */ + uiLayout *sub = uiLayoutColumn(layout, true); + uiLayoutSetEnabled(sub, !id->asset_data); + uiItemO(sub, NULL, ICON_NONE, "ASSET_OT_mark"); + sub = uiLayoutColumn(layout, true); + uiLayoutSetEnabled(sub, id->asset_data); + uiItemO(sub, NULL, ICON_NONE, "ASSET_OT_clear"); + uiItemS(layout); + } + /* Pointer properties and string properties with * prop_search support jumping to target object/bone. */ if (but->rnapoin.data && but->rnaprop) { @@ -1210,6 +1233,10 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) UI_menutype_draw(C, mt, uiLayoutColumn(layout, false)); } + if (but->context) { + CTX_store_set(C, previous_ctx); + } + return UI_popup_menu_end_or_cancel(C, pup); } diff --git a/source/blender/editors/interface/interface_eyedropper_gpencil_color.c b/source/blender/editors/interface/interface_eyedropper_gpencil_color.c index 7f735a0e789..f2899fc0098 100644 --- a/source/blender/editors/interface/interface_eyedropper_gpencil_color.c +++ b/source/blender/editors/interface/interface_eyedropper_gpencil_color.c @@ -34,6 +34,7 @@ #include "BLT_translation.h" #include "DNA_gpencil_types.h" +#include "DNA_material_types.h" #include "DNA_space_types.h" #include "BKE_context.h" diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index f914ccd7497..790c2cd5313 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -334,6 +334,7 @@ typedef struct uiHandleButtonData { int retval; /* booleans (could be made into flags) */ bool cancel, escapecancel; + bool skip_undo_push; bool applied, applied_interactive; bool changed_cursor; wmTimer *flashtimer; @@ -626,7 +627,11 @@ static bool ui_rna_is_userdef(PointerRNA *ptr, PropertyRNA *prop) if (base == NULL) { base = ptr->type; } - if (ELEM(base, &RNA_AddonPreferences, &RNA_KeyConfigPreferences, &RNA_KeyMapItem)) { + if (ELEM(base, + &RNA_AddonPreferences, + &RNA_KeyConfigPreferences, + &RNA_KeyMapItem, + &RNA_UserAssetLibrary)) { tag = true; } } @@ -816,7 +821,9 @@ static void ui_apply_but_func(bContext *C, uiBut *but) /* typically call ui_apply_but_undo(), ui_apply_but_autokey() */ static void ui_apply_but_undo(uiBut *but) { - if (but->flag & UI_BUT_UNDO) { + const bool force_skip_undo = (but->active && but->active->skip_undo_push); + + if (but->flag & UI_BUT_UNDO && !force_skip_undo) { const char *str = NULL; size_t str_len_clip = SIZE_MAX - 1; bool skip_undo = false; @@ -1349,6 +1356,9 @@ static void ui_multibut_states_apply(bContext *C, uiHandleButtonData *data, uiBl if (mbut_state == NULL) { /* Highly unlikely. */ printf("%s: Can't find button\n", __func__); + /* While this avoids crashing, multi-button dragging will fail, + * which is still a bug from the user perspective. See T83651. */ + continue; } void *active_back; @@ -1984,6 +1994,8 @@ static bool ui_but_drag_init(bContext *C, else { wmDrag *drag = WM_event_start_drag( C, but->icon, but->dragtype, but->dragpoin, ui_but_value_get(but), WM_DRAG_NOP); + /* wmDrag has ownership over dragpoin now, stop messing with it. */ + but->dragpoin = NULL; if (but->imb) { WM_event_drag_image(drag, @@ -2256,10 +2268,11 @@ static void ui_but_drop(bContext *C, const wmEvent *event, uiBut *but, uiHandleB ListBase *drags = event->customdata; /* drop event type has listbase customdata by default */ LISTBASE_FOREACH (wmDrag *, wmd, drags) { + /* TODO asset dropping. */ if (wmd->type == WM_DRAG_ID) { /* align these types with UI_but_active_drop_name */ if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) { - ID *id = WM_drag_ID(wmd, 0); + ID *id = WM_drag_get_local_ID(wmd, 0); button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); @@ -2856,7 +2869,8 @@ void ui_but_active_string_clear_and_exit(bContext *C, uiBut *but) but->active->str[0] = 0; ui_apply_but_TEX(C, but, but->active); - button_activate_state(C, but, BUTTON_STATE_EXIT); + /* use onfree event so undo is handled by caller and apply is already done above */ + button_activate_exit((bContext *)C, but, but->active, false, true); } static void ui_textedit_string_ensure_max_length(uiBut *but, uiHandleButtonData *data, int maxlen) @@ -4001,16 +4015,38 @@ static void ui_numedit_apply(bContext *C, uiBlock *block, uiBut *but, uiHandleBu ED_region_tag_redraw(data->region); } -static void ui_but_extra_operator_icon_apply(bContext *C, uiBut *but, uiButExtraOpIcon *op_icon) +static void ui_but_extra_operator_icon_apply_func(uiBut *but, uiButExtraOpIcon *op_icon) { - if (but->active->interactive) { - ui_apply_but(C, but->block, but, but->active, true); + if (ui_afterfunc_check(but->block, but)) { + uiAfterFunc *after = ui_afterfunc_new(); + + after->optype = op_icon->optype_params->optype; + after->opcontext = op_icon->optype_params->opcontext; + after->opptr = op_icon->optype_params->opptr; + + if (but->context) { + after->context = CTX_store_copy(but->context); + } + + /* Ownership moved, don't let the UI code free it. */ + op_icon->optype_params->opptr = NULL; } +} + +static void ui_but_extra_operator_icon_apply(bContext *C, + uiBut *but, + uiHandleButtonData *data, + uiButExtraOpIcon *op_icon) +{ button_activate_state(C, but, BUTTON_STATE_EXIT); - WM_operator_name_call_ptr(C, - op_icon->optype_params->optype, - op_icon->optype_params->opcontext, - op_icon->optype_params->opptr); + ui_apply_but(C, but->block, but, data, true); + + data->postbut = but; + data->posttype = BUTTON_ACTIVATE_OVER; + /* Leave undo up to the operator. */ + data->skip_undo_push = true; + + ui_but_extra_operator_icon_apply_func(but, op_icon); /* Force recreation of extra operator icons (pseudo update). */ ui_but_extra_operator_icons_free(but); @@ -4209,7 +4245,7 @@ static bool ui_do_but_extra_operator_icon(bContext *C, ED_region_tag_redraw(data->region); button_tooltip_timer_reset(C, but); - ui_but_extra_operator_icon_apply(C, but, op_icon); + ui_but_extra_operator_icon_apply(C, but, data, op_icon); /* Note: 'but', 'data' may now be freed, don't access. */ return true; @@ -5851,7 +5887,7 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co if (ELEM(event->type, MOUSEPAN, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->ctrl) { ColorPicker *cpicker = but->custom_data; float hsv_static[3] = {0.0f}; - float *hsv = cpicker ? cpicker->color_data : hsv_static; + float *hsv = cpicker ? cpicker->hsv_perceptual : hsv_static; float col[3]; ui_but_v3_get(but, col); @@ -6079,7 +6115,7 @@ static bool ui_numedit_but_HSVCUBE(uiBut *but, { const uiButHSVCube *hsv_but = (uiButHSVCube *)but; ColorPicker *cpicker = but->custom_data; - float *hsv = cpicker->color_data; + float *hsv = cpicker->hsv_perceptual; float rgb[3]; float x, y; float mx_fl, my_fl; @@ -6097,7 +6133,7 @@ static bool ui_numedit_but_HSVCUBE(uiBut *but, #endif ui_but_v3_get(but, rgb); - ui_scene_linear_to_color_picker_space(but, rgb); + ui_scene_linear_to_perceptual_space(but, rgb); ui_rgb_to_color_picker_HSVCUBE_compat_v(hsv_but, rgb, hsv); @@ -6110,7 +6146,7 @@ static bool ui_numedit_but_HSVCUBE(uiBut *but, /* calculate original hsv again */ copy_v3_v3(rgb, data->origvec); - ui_scene_linear_to_color_picker_space(but, rgb); + ui_scene_linear_to_perceptual_space(but, rgb); copy_v3_v3(hsvo, hsv); @@ -6173,7 +6209,7 @@ static bool ui_numedit_but_HSVCUBE(uiBut *but, } ui_color_picker_to_rgb_HSVCUBE_v(hsv_but, hsv, rgb); - ui_color_picker_to_scene_linear_space(but, rgb); + ui_perceptual_to_scene_linear_space(but, rgb); /* clamp because with color conversion we can exceed range T34295. */ if (hsv_but->gradient_type == UI_GRAD_V_ALT) { @@ -6196,13 +6232,13 @@ static void ui_ndofedit_but_HSVCUBE(uiButHSVCube *hsv_but, const bool shift) { ColorPicker *cpicker = hsv_but->but.custom_data; - float *hsv = cpicker->color_data; + float *hsv = cpicker->hsv_perceptual; const float hsv_v_max = max_ff(hsv[2], hsv_but->but.softmax); float rgb[3]; const float sensitivity = (shift ? 0.15f : 0.3f) * ndof->dt; ui_but_v3_get(&hsv_but->but, rgb); - ui_scene_linear_to_color_picker_space(&hsv_but->but, rgb); + ui_scene_linear_to_perceptual_space(&hsv_but->but, rgb); ui_rgb_to_color_picker_HSVCUBE_compat_v(hsv_but, rgb, hsv); switch (hsv_but->gradient_type) { @@ -6251,7 +6287,7 @@ static void ui_ndofedit_but_HSVCUBE(uiButHSVCube *hsv_but, hsv_clamp_v(hsv, hsv_v_max); ui_color_picker_to_rgb_HSVCUBE_v(hsv_but, hsv, rgb); - ui_color_picker_to_scene_linear_space(&hsv_but->but, rgb); + ui_perceptual_to_scene_linear_space(&hsv_but->but, rgb); copy_v3_v3(data->vec, rgb); ui_but_v3_set(&hsv_but->but, data->vec); @@ -6308,7 +6344,7 @@ static int ui_do_but_HSVCUBE( float rgb[3], def_hsv[3]; float def[4]; ColorPicker *cpicker = but->custom_data; - float *hsv = cpicker->color_data; + float *hsv = cpicker->hsv_perceptual; RNA_property_float_get_default_array(&but->rnapoin, but->rnaprop, def); ui_rgb_to_color_picker_HSVCUBE_v(hsv_but, def, def_hsv); @@ -6364,7 +6400,7 @@ static bool ui_numedit_but_HSVCIRCLE(uiBut *but, { const bool changed = true; ColorPicker *cpicker = but->custom_data; - float *hsv = cpicker->color_data; + float *hsv = cpicker->hsv_perceptual; float mx_fl, my_fl; ui_mouse_scale_warp(data, mx, my, &mx_fl, &my_fl, shift); @@ -6390,8 +6426,8 @@ static bool ui_numedit_but_HSVCIRCLE(uiBut *but, float rgb[3]; ui_but_v3_get(but, rgb); - ui_scene_linear_to_color_picker_space(but, rgb); - ui_rgb_to_color_picker_compat_v(rgb, hsv); + ui_scene_linear_to_perceptual_space(but, rgb); + ui_color_picker_rgb_to_hsv_compat(rgb, hsv); /* exception, when using color wheel in 'locked' value state: * allow choosing a hue for black values, by giving a tiny increment */ @@ -6418,8 +6454,8 @@ static bool ui_numedit_but_HSVCIRCLE(uiBut *but, /* calculate original hsv again */ copy_v3_v3(hsvo, hsv); copy_v3_v3(rgbo, data->origvec); - ui_scene_linear_to_color_picker_space(but, rgbo); - ui_rgb_to_color_picker_compat_v(rgbo, hsvo); + ui_scene_linear_to_perceptual_space(but, rgbo); + ui_color_picker_rgb_to_hsv_compat(rgbo, hsvo); /* and original position */ ui_hsvcircle_pos_from_vals(cpicker, &rect, hsvo, &xpos, &ypos); @@ -6438,7 +6474,7 @@ static bool ui_numedit_but_HSVCIRCLE(uiBut *but, ui_color_snap_hue(snap, &hsv[0]); } - ui_color_picker_to_rgb_v(hsv, rgb); + ui_color_picker_hsv_to_rgb(hsv, rgb); if ((cpicker->use_luminosity_lock)) { if (!is_zero_v3(rgb)) { @@ -6446,7 +6482,7 @@ static bool ui_numedit_but_HSVCIRCLE(uiBut *but, } } - ui_color_picker_to_scene_linear_space(but, rgb); + ui_perceptual_to_scene_linear_space(but, rgb); ui_but_v3_set(but, rgb); data->draglastx = mx; @@ -6463,14 +6499,14 @@ static void ui_ndofedit_but_HSVCIRCLE(uiBut *but, const bool shift) { ColorPicker *cpicker = but->custom_data; - float *hsv = cpicker->color_data; + float *hsv = cpicker->hsv_perceptual; float rgb[3]; float phi, r /*, sqr */ /* UNUSED */, v[2]; const float sensitivity = (shift ? 0.06f : 0.3f) * ndof->dt; ui_but_v3_get(but, rgb); - ui_scene_linear_to_color_picker_space(but, rgb); - ui_rgb_to_color_picker_compat_v(rgb, hsv); + ui_scene_linear_to_perceptual_space(but, rgb); + ui_color_picker_rgb_to_hsv_compat(rgb, hsv); /* Convert current color on hue/sat disc to circular coordinates phi, r */ phi = fmodf(hsv[0] + 0.25f, 1.0f) * -2.0f * (float)M_PI; @@ -6520,7 +6556,7 @@ static void ui_ndofedit_but_HSVCIRCLE(uiBut *but, hsv_clamp_v(hsv, FLT_MAX); - ui_color_picker_to_rgb_v(hsv, data->vec); + ui_color_picker_hsv_to_rgb(hsv, data->vec); if (cpicker->use_luminosity_lock) { if (!is_zero_v3(data->vec)) { @@ -6528,7 +6564,7 @@ static void ui_ndofedit_but_HSVCIRCLE(uiBut *but, } } - ui_color_picker_to_scene_linear_space(but, data->vec); + ui_perceptual_to_scene_linear_space(but, data->vec); ui_but_v3_set(but, data->vec); } #endif /* WITH_INPUT_NDOF */ @@ -6537,7 +6573,7 @@ static int ui_do_but_HSVCIRCLE( bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) { ColorPicker *cpicker = but->custom_data; - float *hsv = cpicker->color_data; + float *hsv = cpicker->hsv_perceptual; int mx = event->x; int my = event->y; ui_window_to_block(data->region, block, &mx, &my); @@ -6584,10 +6620,10 @@ static int ui_do_but_HSVCIRCLE( def = MEM_callocN(sizeof(float) * len, "reset_defaults - float"); RNA_property_float_get_default_array(&but->rnapoin, but->rnaprop, def); - ui_color_picker_to_rgb_v(def, def_hsv); + ui_color_picker_hsv_to_rgb(def, def_hsv); ui_but_v3_get(but, rgb); - ui_rgb_to_color_picker_compat_v(rgb, hsv); + ui_color_picker_rgb_to_hsv_compat(rgb, hsv); def_hsv[0] = hsv[0]; def_hsv[2] = hsv[2]; @@ -7844,7 +7880,10 @@ static ARegion *ui_but_tooltip_init( uiBut *but = UI_region_active_but_get(region); *r_exit_on_event = false; if (but) { - return UI_tooltip_create_from_button(C, region, but, is_label); + uiButExtraOpIcon *extra_icon = ui_but_extra_operator_icon_mouse_over_get( + but, but->active, CTX_wm_window(C)->eventstate); + + return UI_tooltip_create_from_button_or_extra_icon(C, region, but, extra_icon, is_label); } return NULL; } diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index 90f5172f6ec..899f4a6ddb1 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -100,11 +100,12 @@ typedef void (*VectorDrawFunc)(int x, int y, int w, int h, float alpha); #define ICON_TYPE_COLOR_TEXTURE 1 #define ICON_TYPE_MONO_TEXTURE 2 #define ICON_TYPE_BUFFER 3 -#define ICON_TYPE_VECTOR 4 -#define ICON_TYPE_GEOM 5 -#define ICON_TYPE_EVENT 6 /* draw keymap entries using custom renderer. */ -#define ICON_TYPE_GPLAYER 7 -#define ICON_TYPE_BLANK 8 +#define ICON_TYPE_IMBUF 4 +#define ICON_TYPE_VECTOR 5 +#define ICON_TYPE_GEOM 6 +#define ICON_TYPE_EVENT 7 /* draw keymap entries using custom renderer. */ +#define ICON_TYPE_GPLAYER 8 +#define ICON_TYPE_BLANK 9 typedef struct DrawInfo { int type; @@ -1147,6 +1148,9 @@ static DrawInfo *icon_create_drawinfo(Icon *icon) if (ELEM(icon_data_type, ICON_DATA_ID, ICON_DATA_PREVIEW)) { di->type = ICON_TYPE_PREVIEW; } + else if (icon_data_type == ICON_DATA_IMBUF) { + di->type = ICON_TYPE_IMBUF; + } else if (icon_data_type == ICON_DATA_GEOM) { di->type = ICON_TYPE_GEOM; } @@ -1262,7 +1266,7 @@ static void icon_create_rect(struct PreviewImage *prv_img, enum eIconSizes size) else if (!prv_img->rect[size]) { prv_img->w[size] = render_size; prv_img->h[size] = render_size; - prv_img->flag[size] |= PRV_CHANGED; + prv_img->flag[size] |= (PRV_CHANGED | PRV_UNFINISHED); prv_img->changed_timestamp[size] = 0; prv_img->rect[size] = MEM_callocN(render_size * render_size * sizeof(uint), "prv_rect"); } @@ -1384,8 +1388,12 @@ void ui_icon_ensure_deferred(const bContext *C, const int icon_id, const bool bi } } -/* only called when icon has changed */ -/* only call with valid pointer from UI_icon_draw */ +/** + * * Only call with valid pointer from UI_icon_draw. + * * Only called when icon has changed. + * + * Note that if an ID doesn't support jobs for preview creation, \a use_job will be ignored. + */ static void icon_set_image(const bContext *C, Scene *scene, ID *id, @@ -1408,7 +1416,7 @@ static void icon_set_image(const bContext *C, const bool delay = prv_img->rect[size] != NULL; icon_create_rect(prv_img, size); - if (use_job) { + if (use_job && (!id || BKE_previewimg_id_supports_jobs(id))) { /* Job (background) version */ ED_preview_icon_job( C, prv_img, id, prv_img->rect[size], prv_img->w[size], prv_img->h[size], delay); @@ -1790,7 +1798,14 @@ static void icon_draw_size(float x, /* We need to flush widget base first to ensure correct ordering. */ UI_widgetbase_draw_cache_flush(); - if (di->type == ICON_TYPE_VECTOR) { + if (di->type == ICON_TYPE_IMBUF) { + ImBuf *ibuf = icon->obj; + + GPU_blend(GPU_BLEND_ALPHA_PREMULT); + icon_draw_rect(x, y, w, h, aspect, ibuf->x, ibuf->y, ibuf->rect, alpha, desaturate); + GPU_blend(GPU_BLEND_ALPHA); + } + else if (di->type == ICON_TYPE_VECTOR) { /* vector icons use the uiBlock transformation, they are not drawn * with untransformed coordinates like the other icons */ di->data.vector.func((int)x, (int)y, w, h, 1.0f); @@ -1937,6 +1952,9 @@ static void ui_id_preview_image_render_size( } } +/** + * Note that if an ID doesn't support jobs for preview creation, \a use_job will be ignored. + */ void UI_icon_render_id(const bContext *C, Scene *scene, ID *id, const bool big, const bool use_job) { PreviewImage *pi = BKE_previewimg_id_ensure(id); @@ -1964,12 +1982,7 @@ static void ui_id_icon_render(const bContext *C, ID *id, bool use_jobs) } for (enum eIconSizes i = 0; i < NUM_ICON_SIZES; i++) { - /* check if rect needs to be created; changed - * only set by dynamic icons */ - if (((pi->flag[i] & PRV_CHANGED) || !pi->rect[i])) { - icon_set_image(C, NULL, id, pi, i, use_jobs); - pi->flag[i] &= ~PRV_CHANGED; - } + ui_id_preview_image_render_size(C, NULL, id, pi, i, use_jobs); } } @@ -2186,6 +2199,9 @@ int UI_icon_from_library(const ID *id) if (ID_IS_OVERRIDE_LIBRARY(id)) { return ICON_LIBRARY_DATA_OVERRIDE; } + if (ID_IS_ASSET(id)) { + return ICON_MAT_SPHERE_SKY; + } return ICON_NONE; } diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 5c7cad4c8d5..c005b456b6a 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -220,8 +220,8 @@ struct uiBut { const char *disabled_info; BIFIconID icon; - /** emboss: UI_EMBOSS, UI_EMBOSS_NONE ... etc, copied from the #uiBlock.emboss */ - char emboss; + /** Copied from the #uiBlock.emboss */ + eUIEmbossType emboss; /** direction in a pie menu, used for collision detection (RadialDirection) */ signed char pie_dir; /** could be made into a single flag */ @@ -378,11 +378,20 @@ typedef struct uiButExtraOpIcon { typedef struct ColorPicker { struct ColorPicker *next, *prev; - /** Color data, may be HSV or HSL. */ - float color_data[3]; - /** Initial color data (detect changes). */ - float color_data_init[3]; + + /** Color in HSV or HSL, in color picking color space. Used for HSV cube, + * circle and slider widgets. The color picking space is perceptually + * linear for intuitive editing. */ + float hsv_perceptual[3]; + /** Initial color data (to detect changes). */ + float hsv_perceptual_init[3]; bool is_init; + + /** HSV or HSL color in scene linear color space value used for number + * buttons. This is scene linear so that there is a clear correspondence + * to the scene linear RGB values. */ + float hsv_scene_linear[3]; + /** Cubic saturation for the color wheel. */ bool use_color_cubic; bool use_color_lock; @@ -493,8 +502,8 @@ struct uiBlock { char direction; /** UI_BLOCK_THEME_STYLE_* */ char theme_style; - /** UI_EMBOSS, UI_EMBOSS_NONE ... etc, copied to #uiBut.emboss */ - char emboss; + /** Copied to #uiBut.emboss */ + eUIEmbossType emboss; bool auto_open; char _pad[5]; double auto_open_last; @@ -734,15 +743,14 @@ struct uiPopupBlockHandle { /* exposed as public API in UI_interface.h */ /* interface_region_color_picker.c */ -void ui_rgb_to_color_picker_compat_v(const float rgb[3], float r_cp[3]); -void ui_rgb_to_color_picker_v(const float rgb[3], float r_cp[3]); -void ui_color_picker_to_rgb_v(const float r_cp[3], float rgb[3]); -void ui_color_picker_to_rgb(float r_cp0, float r_cp1, float r_cp2, float *r, float *g, float *b); +void ui_color_picker_rgb_to_hsv_compat(const float rgb[3], float r_cp[3]); +void ui_color_picker_rgb_to_hsv(const float rgb[3], float r_cp[3]); +void ui_color_picker_hsv_to_rgb(const float r_cp[3], float rgb[3]); bool ui_but_is_color_gamma(uiBut *but); -void ui_scene_linear_to_color_picker_space(uiBut *but, float rgb[3]); -void ui_color_picker_to_scene_linear_space(uiBut *but, float rgb[3]); +void ui_scene_linear_to_perceptual_space(uiBut *but, float rgb[3]); +void ui_perceptual_to_scene_linear_space(uiBut *but, float rgb[3]); uiBlock *ui_block_func_COLOR(struct bContext *C, uiPopupBlockHandle *handle, void *arg_but); ColorPicker *ui_block_colorpicker_create(struct uiBlock *block); diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 0403287125c..3ea7a5f5973 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -172,7 +172,7 @@ struct uiLayout { /** For layouts inside gridflow, they and their items shall never have a fixed maximal size. */ bool variable_size; char alignment; - char emboss; + eUIEmbossType emboss; /** for fixed width or height to avoid UI size changes */ float units[2]; }; @@ -651,7 +651,7 @@ static void ui_item_array(uiLayout *layout, uiDefAutoButR(block, ptr, prop, -1, "", ICON_NONE, 0, 0, w, UI_UNIT_Y); } else { - /* even if 'expand' is fale, expanding anyway */ + /* Even if 'expand' is false, we expand anyway. */ /* layout for known array subtypes */ char str[3] = {'\0'}; @@ -1189,7 +1189,7 @@ static uiBut *uiItemFullO_ptr_ex(uiLayout *layout, const int w = ui_text_icon_width(layout, name, icon, 0); - const int prev_emboss = layout->emboss; + const eUIEmbossType prev_emboss = layout->emboss; if (flag & UI_ITEM_R_NO_BG) { layout->emboss = UI_EMBOSS_NONE; } @@ -2120,7 +2120,7 @@ void uiItemFullR(uiLayout *layout, int w, h; ui_item_rna_size(layout, name, icon, ptr, prop, index, icon_only, compact, &w, &h); - const int prev_emboss = layout->emboss; + const eUIEmbossType prev_emboss = layout->emboss; if (no_bg) { layout->emboss = UI_EMBOSS_NONE; } @@ -3457,8 +3457,6 @@ static void menu_item_enum_rna_menu(bContext *UNUSED(C), uiLayout *layout, void void uiItemMenuEnumR_prop( uiLayout *layout, struct PointerRNA *ptr, PropertyRNA *prop, const char *name, int icon) { - MenuItemLevel *lvl; - if (!name) { name = RNA_property_ui_name(prop); } @@ -3466,7 +3464,7 @@ void uiItemMenuEnumR_prop( icon = ICON_BLANK1; } - lvl = MEM_callocN(sizeof(MenuItemLevel), "MenuItemLevel"); + MenuItemLevel *lvl = MEM_callocN(sizeof(MenuItemLevel), "MenuItemLevel"); lvl->rnapoin = *ptr; BLI_strncpy(lvl->propname, RNA_property_identifier(prop), sizeof(lvl->propname)); lvl->opcontext = layout->root->opcontext; @@ -3550,15 +3548,15 @@ static int ui_litem_min_width(int itemw) static void ui_litem_layout_row(uiLayout *litem) { uiItem *last_free_item = NULL; - int x, y, w, tot, totw, neww, newtotw, itemw, minw, itemh, offset; - int fixedw, freew, fixedx, freex, flag = 0, lastw = 0; + int x, neww, newtotw, itemw, minw, itemh, offset; + int freew, fixedx, freex, flag = 0, lastw = 0; float extra_pixel; /* x = litem->x; */ /* UNUSED */ - y = litem->y; - w = litem->w; - totw = 0; - tot = 0; + int y = litem->y; + int w = litem->w; + int totw = 0; + int tot = 0; LISTBASE_FOREACH (uiItem *, item, &litem->items) { ui_item_size(item, &itemw, &itemh); @@ -3573,7 +3571,7 @@ static void ui_litem_layout_row(uiLayout *litem) if (w != 0) { w -= (tot - 1) * litem->space; } - fixedw = 0; + int fixedw = 0; /* keep clamping items to fixed minimum size until all are done */ do { @@ -3724,12 +3722,11 @@ static void ui_litem_estimate_column(uiLayout *litem, bool is_box) static void ui_litem_layout_column(uiLayout *litem, bool is_box, bool is_menu) { - int itemw, itemh, x, y; - - x = litem->x; - y = litem->y; + int x = litem->x; + int y = litem->y; LISTBASE_FOREACH (uiItem *, item, &litem->items) { + int itemw, itemh; ui_item_size(item, &itemw, &itemh); y -= itemh; @@ -3753,15 +3750,13 @@ static void ui_litem_layout_column(uiLayout *litem, bool is_box, bool is_menu) * stores a float vector in unit circle */ static RadialDirection ui_get_radialbut_vec(float vec[2], short itemnum) { - RadialDirection dir; - if (itemnum >= PIE_MAX_ITEMS) { itemnum %= PIE_MAX_ITEMS; printf("Warning: Pie menus with more than %i items are currently unsupported\n", PIE_MAX_ITEMS); } - dir = ui_radial_dir_order[itemnum]; + RadialDirection dir = ui_radial_dir_order[itemnum]; ui_but_pie_dir(dir, vec); return dir; @@ -3789,7 +3784,7 @@ static bool ui_item_is_radial_drawable(uiButtonItem *bitem) static void ui_litem_layout_radial(uiLayout *litem) { - int itemh, itemw, x, y; + int itemh, itemw; int itemnum = 0; int totitems = 0; @@ -3800,8 +3795,8 @@ static void ui_litem_layout_radial(uiLayout *litem) const int pie_radius = U.pie_menu_radius * UI_DPI_FAC; - x = litem->x; - y = litem->y; + int x = litem->x; + int y = litem->y; int minx = x, miny = y, maxx = x, maxy = y; @@ -3921,16 +3916,14 @@ static void ui_litem_layout_box(uiLayout *litem) { uiLayoutItemBx *box = (uiLayoutItemBx *)litem; const uiStyle *style = litem->root->style; - uiBut *but; - int w, h; int boxspace = style->boxspace; if (litem->root->type == UI_LAYOUT_HEADER) { boxspace = 0; } - w = litem->w; - h = litem->h; + int w = litem->w; + int h = litem->h; litem->x += boxspace; litem->y -= boxspace; @@ -3955,7 +3948,7 @@ static void ui_litem_layout_box(uiLayout *litem) } /* roundbox around the sublayout */ - but = box->roundbox; + uiBut *but = box->roundbox; but->rect.xmin = litem->x; but->rect.ymin = litem->y; but->rect.xmax = litem->x + litem->w; @@ -3967,12 +3960,11 @@ static void ui_litem_estimate_column_flow(uiLayout *litem) { const uiStyle *style = litem->root->style; uiLayoutItemFlow *flow = (uiLayoutItemFlow *)litem; - int col, x, y, emh, emy, miny, itemw, itemh, maxw = 0; - int toth, totitem; + int itemw, itemh, maxw = 0; /* compute max needed width and total height */ - toth = 0; - totitem = 0; + int toth = 0; + int totitem = 0; LISTBASE_FOREACH (uiItem *, item, &litem->items) { ui_item_size(item, &itemw, &itemh); maxw = MAX2(maxw, itemw); @@ -3995,16 +3987,16 @@ static void ui_litem_estimate_column_flow(uiLayout *litem) } /* compute sizes */ - x = 0; - y = 0; - emy = 0; - miny = 0; + int x = 0; + int y = 0; + int emy = 0; + int miny = 0; maxw = 0; - emh = toth / flow->totcol; + int emh = toth / flow->totcol; /* create column per column */ - col = 0; + int col = 0; LISTBASE_FOREACH (uiItem *, item, &litem->items) { ui_item_size(item, &itemw, &itemh); @@ -4031,12 +4023,11 @@ static void ui_litem_layout_column_flow(uiLayout *litem) { const uiStyle *style = litem->root->style; uiLayoutItemFlow *flow = (uiLayoutItemFlow *)litem; - int col, x, y, w, emh, emy, miny, itemw, itemh; - int toth, totitem; + int col, emh, itemw, itemh; /* compute max needed width and total height */ - toth = 0; - totitem = 0; + int toth = 0; + int totitem = 0; LISTBASE_FOREACH (uiItem *, item, &litem->items) { ui_item_size(item, &itemw, &itemh); toth += itemh; @@ -4044,12 +4035,12 @@ static void ui_litem_layout_column_flow(uiLayout *litem) } /* compute sizes */ - x = litem->x; - y = litem->y; - emy = 0; - miny = 0; + int x = litem->x; + int y = litem->y; + int emy = 0; + int miny = 0; - w = litem->w - (flow->totcol - 1) * style->columnspace; + int w = litem->w - (flow->totcol - 1) * style->columnspace; emh = toth / flow->totcol; /* create column per column */ @@ -4457,14 +4448,13 @@ static void ui_litem_layout_grid_flow(uiLayout *litem) /* free layout */ static void ui_litem_estimate_absolute(uiLayout *litem) { - int itemx, itemy, itemw, itemh, minx, miny; - - minx = 1e6; - miny = 1e6; + int minx = 1e6; + int miny = 1e6; litem->w = 0; litem->h = 0; LISTBASE_FOREACH (uiItem *, item, &litem->items) { + int itemx, itemy, itemw, itemh; ui_item_offset(item, &itemx, &itemy); ui_item_size(item, &itemw, &itemh); @@ -4482,12 +4472,12 @@ static void ui_litem_estimate_absolute(uiLayout *litem) static void ui_litem_layout_absolute(uiLayout *litem) { float scalex = 1.0f, scaley = 1.0f; - int x, y, newx, newy, itemx, itemy, itemh, itemw, minx, miny, totw, toth; + int x, y, newx, newy, itemx, itemy, itemh, itemw; - minx = 1e6; - miny = 1e6; - totw = 0; - toth = 0; + int minx = 1e6; + int miny = 1e6; + int totw = 0; + int toth = 0; LISTBASE_FOREACH (uiItem *, item, &litem->items) { ui_item_offset(item, &itemx, &itemy); @@ -4548,24 +4538,24 @@ static void ui_litem_estimate_split(uiLayout *litem) static void ui_litem_layout_split(uiLayout *litem) { uiLayoutItemSplit *split = (uiLayoutItemSplit *)litem; - float percentage, extra_pixel = 0.0f; + float extra_pixel = 0.0f; const int tot = BLI_listbase_count(&litem->items); - int itemh, x, y, w, colw = 0; if (tot == 0) { return; } - x = litem->x; - y = litem->y; + int x = litem->x; + int y = litem->y; - percentage = (split->percentage == 0.0f) ? 1.0f / (float)tot : split->percentage; + float percentage = (split->percentage == 0.0f) ? 1.0f / (float)tot : split->percentage; - w = (litem->w - (tot - 1) * litem->space); - colw = w * percentage; + int w = (litem->w - (tot - 1) * litem->space); + int colw = w * percentage; colw = MAX2(colw, 0); LISTBASE_FOREACH (uiItem *, item, &litem->items) { + int itemh; ui_item_size(item, NULL, &itemh); ui_item_position(item, x, y - itemh, colw, itemh); @@ -4590,12 +4580,11 @@ static void ui_litem_layout_split(uiLayout *litem) /* overlap layout */ static void ui_litem_estimate_overlap(uiLayout *litem) { - int itemw, itemh; - litem->w = 0; litem->h = 0; LISTBASE_FOREACH (uiItem *, item, &litem->items) { + int itemw, itemh; ui_item_size(item, &itemw, &itemh); litem->w = MAX2(itemw, litem->w); @@ -4605,12 +4594,12 @@ static void ui_litem_estimate_overlap(uiLayout *litem) static void ui_litem_layout_overlap(uiLayout *litem) { - int itemw, itemh, x, y; - x = litem->x; - y = litem->y; + int x = litem->x; + int y = litem->y; LISTBASE_FOREACH (uiItem *, item, &litem->items) { + int itemw, itemh; ui_item_size(item, &itemw, &itemh); ui_item_position(item, x, y - itemh, litem->w, itemh); @@ -4657,9 +4646,7 @@ static void ui_layout_heading_set(uiLayout *layout, const char *heading) /* layout create functions */ uiLayout *uiLayoutRow(uiLayout *layout, bool align) { - uiLayout *litem; - - litem = MEM_callocN(sizeof(uiLayout), "uiLayoutRow"); + uiLayout *litem = MEM_callocN(sizeof(uiLayout), "uiLayoutRow"); ui_litem_init_from_parent(litem, layout, align); litem->item.type = ITEM_LAYOUT_ROW; @@ -4682,9 +4669,7 @@ uiLayout *uiLayoutRowWithHeading(uiLayout *layout, bool align, const char *headi uiLayout *uiLayoutColumn(uiLayout *layout, bool align) { - uiLayout *litem; - - litem = MEM_callocN(sizeof(uiLayout), "uiLayoutColumn"); + uiLayout *litem = MEM_callocN(sizeof(uiLayout), "uiLayoutColumn"); ui_litem_init_from_parent(litem, layout, align); litem->item.type = ITEM_LAYOUT_COLUMN; @@ -4710,9 +4695,7 @@ uiLayout *uiLayoutColumnWithHeading(uiLayout *layout, bool align, const char *he uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, bool align) { - uiLayoutItemFlow *flow; - - flow = MEM_callocN(sizeof(uiLayoutItemFlow), "uiLayoutItemFlow"); + uiLayoutItemFlow *flow = MEM_callocN(sizeof(uiLayoutItemFlow), "uiLayoutItemFlow"); ui_litem_init_from_parent(&flow->litem, layout, align); flow->litem.item.type = ITEM_LAYOUT_COLUMN_FLOW; @@ -4731,9 +4714,7 @@ uiLayout *uiLayoutGridFlow(uiLayout *layout, bool even_rows, bool align) { - uiLayoutItemGridFlow *flow; - - flow = MEM_callocN(sizeof(uiLayoutItemGridFlow), __func__); + uiLayoutItemGridFlow *flow = MEM_callocN(sizeof(uiLayoutItemGridFlow), __func__); flow->litem.item.type = ITEM_LAYOUT_GRID_FLOW; ui_litem_init_from_parent(&flow->litem, layout, align); @@ -4750,9 +4731,7 @@ uiLayout *uiLayoutGridFlow(uiLayout *layout, static uiLayoutItemBx *ui_layout_box(uiLayout *layout, int type) { - uiLayoutItemBx *box; - - box = MEM_callocN(sizeof(uiLayoutItemBx), "uiLayoutItemBx"); + uiLayoutItemBx *box = MEM_callocN(sizeof(uiLayoutItemBx), "uiLayoutItemBx"); ui_litem_init_from_parent(&box->litem, layout, false); box->litem.item.type = ITEM_LAYOUT_BOX; @@ -4767,8 +4746,6 @@ static uiLayoutItemBx *ui_layout_box(uiLayout *layout, int type) uiLayout *uiLayoutRadial(uiLayout *layout) { - uiLayout *litem; - /* radial layouts are only valid for radial menus */ if (layout->root->type != UI_LAYOUT_PIEMENU) { return ui_item_local_sublayout(layout, layout, 0); @@ -4776,14 +4753,14 @@ uiLayout *uiLayoutRadial(uiLayout *layout) /* only one radial wheel per root layout is allowed, so check and return that, if it exists */ LISTBASE_FOREACH (uiItem *, item, &layout->root->layout->items) { - litem = (uiLayout *)item; + uiLayout *litem = (uiLayout *)item; if (litem->item.type == ITEM_LAYOUT_RADIAL) { UI_block_layout_set_current(layout->root->block, litem); return litem; } } - litem = MEM_callocN(sizeof(uiLayout), "uiLayoutRadial"); + uiLayout *litem = MEM_callocN(sizeof(uiLayout), "uiLayoutRadial"); ui_litem_init_from_parent(litem, layout, false); litem->item.type = ITEM_LAYOUT_RADIAL; @@ -4838,9 +4815,7 @@ uiLayout *uiLayoutListBox(uiLayout *layout, uiLayout *uiLayoutAbsolute(uiLayout *layout, bool align) { - uiLayout *litem; - - litem = MEM_callocN(sizeof(uiLayout), "uiLayoutAbsolute"); + uiLayout *litem = MEM_callocN(sizeof(uiLayout), "uiLayoutAbsolute"); ui_litem_init_from_parent(litem, layout, align); litem->item.type = ITEM_LAYOUT_ABSOLUTE; @@ -4852,9 +4827,7 @@ uiLayout *uiLayoutAbsolute(uiLayout *layout, bool align) uiBlock *uiLayoutAbsoluteBlock(uiLayout *layout) { - uiBlock *block; - - block = uiLayoutGetBlock(layout); + uiBlock *block = uiLayoutGetBlock(layout); uiLayoutAbsolute(layout, false); return block; @@ -4862,9 +4835,7 @@ uiBlock *uiLayoutAbsoluteBlock(uiLayout *layout) uiLayout *uiLayoutOverlap(uiLayout *layout) { - uiLayout *litem; - - litem = MEM_callocN(sizeof(uiLayout), "uiLayoutOverlap"); + uiLayout *litem = MEM_callocN(sizeof(uiLayout), "uiLayoutOverlap"); ui_litem_init_from_parent(litem, layout, false); litem->item.type = ITEM_LAYOUT_OVERLAP; @@ -4876,9 +4847,7 @@ uiLayout *uiLayoutOverlap(uiLayout *layout) uiLayout *uiLayoutSplit(uiLayout *layout, float percentage, bool align) { - uiLayoutItemSplit *split; - - split = MEM_callocN(sizeof(uiLayoutItemSplit), "uiLayoutItemSplit"); + uiLayoutItemSplit *split = MEM_callocN(sizeof(uiLayoutItemSplit), "uiLayoutItemSplit"); ui_litem_init_from_parent(&split->litem, layout, align); split->litem.item.type = ITEM_LAYOUT_SPLIT; @@ -4945,7 +4914,7 @@ void uiLayoutSetUnitsY(uiLayout *layout, float unit) layout->units[1] = unit; } -void uiLayoutSetEmboss(uiLayout *layout, char emboss) +void uiLayoutSetEmboss(uiLayout *layout, eUIEmbossType emboss) { layout->emboss = emboss; } @@ -5030,7 +4999,7 @@ float uiLayoutGetUnitsY(uiLayout *layout) return layout->units[1]; } -int uiLayoutGetEmboss(uiLayout *layout) +eUIEmbossType uiLayoutGetEmboss(uiLayout *layout) { if (layout->emboss == UI_EMBOSS_UNDEFINED) { return layout->root->block->emboss; @@ -5290,12 +5259,9 @@ static void ui_item_estimate(uiItem *item) static void ui_item_align(uiLayout *litem, short nr) { - uiButtonItem *bitem; - uiLayoutItemBx *box; - LISTBASE_FOREACH_BACKWARD (uiItem *, item, &litem->items) { if (item->type == ITEM_BUTTON) { - bitem = (uiButtonItem *)item; + uiButtonItem *bitem = (uiButtonItem *)item; #ifndef USE_UIBUT_SPATIAL_ALIGN if (ui_but_can_align(bitem->but)) #endif @@ -5312,7 +5278,7 @@ static void ui_item_align(uiLayout *litem, short nr) /* pass */ } else if (item->type == ITEM_LAYOUT_BOX) { - box = (uiLayoutItemBx *)item; + uiLayoutItemBx *box = (uiLayoutItemBx *)item; if (!box->roundbox->alignnr) { box->roundbox->alignnr = nr; } @@ -5325,11 +5291,9 @@ static void ui_item_align(uiLayout *litem, short nr) static void ui_item_flag(uiLayout *litem, int flag) { - uiButtonItem *bitem; - LISTBASE_FOREACH_BACKWARD (uiItem *, item, &litem->items) { if (item->type == ITEM_BUTTON) { - bitem = (uiButtonItem *)item; + uiButtonItem *bitem = (uiButtonItem *)item; bitem->but->flag |= flag; } else { @@ -5465,17 +5429,14 @@ uiLayout *UI_block_layout(uiBlock *block, int padding, const uiStyle *style) { - uiLayout *layout; - uiLayoutRoot *root; - - root = MEM_callocN(sizeof(uiLayoutRoot), "uiLayoutRoot"); + uiLayoutRoot *root = MEM_callocN(sizeof(uiLayoutRoot), "uiLayoutRoot"); root->type = type; root->style = style; root->block = block; root->padding = padding; root->opcontext = WM_OP_INVOKE_REGION_WIN; - layout = MEM_callocN(sizeof(uiLayout), "uiLayout"); + uiLayout *layout = MEM_callocN(sizeof(uiLayout), "uiLayout"); layout->item.type = (type == UI_LAYOUT_VERT_BAR) ? ITEM_LAYOUT_COLUMN : ITEM_LAYOUT_ROOT; /* Only used when 'UI_ITEM_PROP_SEP' is set. */ @@ -5485,8 +5446,8 @@ uiLayout *UI_block_layout(uiBlock *block, layout->y = y; layout->root = root; layout->space = style->templatespace; - layout->active = 1; - layout->enabled = 1; + layout->active = true; + layout->enabled = true; layout->context = NULL; layout->emboss = UI_EMBOSS_UNDEFINED; @@ -5529,9 +5490,7 @@ void UI_block_layout_set_current(uiBlock *block, uiLayout *layout) void ui_layout_add_but(uiLayout *layout, uiBut *but) { - uiButtonItem *bitem; - - bitem = MEM_callocN(sizeof(uiButtonItem), "uiButtonItem"); + uiButtonItem *bitem = MEM_callocN(sizeof(uiButtonItem), "uiButtonItem"); bitem->item.type = ITEM_BUTTON; bitem->but = but; @@ -5663,6 +5622,11 @@ void uiLayoutSetContextPointer(uiLayout *layout, const char *name, PointerRNA *p layout->context = CTX_store_add(&block->contexts, name, ptr); } +bContextStore *uiLayoutGetContextStore(uiLayout *layout) +{ + return layout->context; +} + void uiLayoutContextCopy(uiLayout *layout, bContextStore *context) { uiBlock *block = layout->root->block; diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 0d1e2802242..2995cff8ed5 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -1223,7 +1223,7 @@ typedef struct uiEditSourceStore { typedef struct uiEditSourceButStore { char py_dbg_fn[FILE_MAX]; - int py_dbg_ln; + int py_dbg_line_number; } uiEditSourceButStore; /* should only ever be set while the edit source operator is running */ @@ -1276,21 +1276,21 @@ void UI_editsource_active_but_test(uiBut *but) struct uiEditSourceButStore *but_store = MEM_callocN(sizeof(uiEditSourceButStore), __func__); const char *fn; - int lineno = -1; + int line_number = -1; # if 0 printf("comparing buttons: '%s' == '%s'\n", but->drawstr, ui_editsource_info->but_orig.drawstr); # endif - PyC_FileAndNum_Safe(&fn, &lineno); + PyC_FileAndNum_Safe(&fn, &line_number); - if (lineno != -1) { + if (line_number != -1) { BLI_strncpy(but_store->py_dbg_fn, fn, sizeof(but_store->py_dbg_fn)); - but_store->py_dbg_ln = lineno; + but_store->py_dbg_line_number = line_number; } else { but_store->py_dbg_fn[0] = '\0'; - but_store->py_dbg_ln = -1; + but_store->py_dbg_line_number = -1; } BLI_ghash_insert(ui_editsource_info->hash, but, but_store); @@ -1375,8 +1375,8 @@ static int editsource_exec(bContext *C, wmOperator *op) } if (but_store) { - if (but_store->py_dbg_ln != -1) { - ret = editsource_text_edit(C, op, but_store->py_dbg_fn, but_store->py_dbg_ln); + if (but_store->py_dbg_line_number != -1) { + ret = editsource_text_edit(C, op, but_store->py_dbg_fn, but_store->py_dbg_line_number); } else { BKE_report( @@ -1521,6 +1521,7 @@ static int edittranslation_exec(bContext *C, wmOperator *op) UI_but_string_info_get(C, but, + NULL, &but_label, &rna_label, &enum_label, diff --git a/source/blender/editors/interface/interface_region_color_picker.c b/source/blender/editors/interface/interface_region_color_picker.c index f9a9e7182d2..82028d4e595 100644 --- a/source/blender/editors/interface/interface_region_color_picker.c +++ b/source/blender/editors/interface/interface_region_color_picker.c @@ -77,8 +77,10 @@ static void ui_color_picker_rgb_round(float rgb[3]) } } -void ui_rgb_to_color_picker_compat_v(const float rgb[3], float r_cp[3]) +void ui_color_picker_rgb_to_hsv_compat(const float rgb[3], float r_cp[3]) { + /* Convert RGB to HSV, remaining as compatible as possible with the existing + * r_hsv value (for example when value goes to zero, preserve the hue). */ switch (U.color_picker_type) { case USER_CP_CIRCLE_HSL: rgb_to_hsl_compat_v(rgb, r_cp); @@ -89,7 +91,7 @@ void ui_rgb_to_color_picker_compat_v(const float rgb[3], float r_cp[3]) } } -void ui_rgb_to_color_picker_v(const float rgb[3], float r_cp[3]) +void ui_color_picker_rgb_to_hsv(const float rgb[3], float r_cp[3]) { switch (U.color_picker_type) { case USER_CP_CIRCLE_HSL: @@ -101,7 +103,7 @@ void ui_rgb_to_color_picker_v(const float rgb[3], float r_cp[3]) } } -void ui_color_picker_to_rgb_v(const float r_cp[3], float rgb[3]) +void ui_color_picker_hsv_to_rgb(const float r_cp[3], float rgb[3]) { switch (U.color_picker_type) { case USER_CP_CIRCLE_HSL: @@ -113,18 +115,6 @@ void ui_color_picker_to_rgb_v(const float r_cp[3], float rgb[3]) } } -void ui_color_picker_to_rgb(float r_cp0, float r_cp1, float r_cp2, float *r, float *g, float *b) -{ - switch (U.color_picker_type) { - case USER_CP_CIRCLE_HSL: - hsl_to_rgb(r_cp0, r_cp1, r_cp2, r, g, b); - break; - default: - hsv_to_rgb(r_cp0, r_cp1, r_cp2, r, g, b); - break; - } -} - /* Returns true if the button is for a color with gamma baked in, * or if it's a color picker for such a button. */ bool ui_but_is_color_gamma(uiBut *but) @@ -138,7 +128,7 @@ bool ui_but_is_color_gamma(uiBut *but) return but->block->is_color_gamma_picker; } -void ui_scene_linear_to_color_picker_space(uiBut *but, float rgb[3]) +void ui_scene_linear_to_perceptual_space(uiBut *but, float rgb[3]) { /* Map to color picking space for HSV values and HSV cube/circle, * assuming it is more perceptually linear than the scene linear @@ -149,7 +139,7 @@ void ui_scene_linear_to_color_picker_space(uiBut *but, float rgb[3]) } } -void ui_color_picker_to_scene_linear_space(uiBut *but, float rgb[3]) +void ui_perceptual_to_scene_linear_space(uiBut *but, float rgb[3]) { if (!ui_but_is_color_gamma(but)) { IMB_colormanagement_color_picking_to_scene_linear_v3(rgb); @@ -163,16 +153,46 @@ void ui_color_picker_to_scene_linear_space(uiBut *but, float rgb[3]) /** \name Color Picker * \{ */ +static void ui_color_picker_update_hsv(ColorPicker *cpicker, + uiBut *from_but, + const float rgb_scene_linear[3]) +{ + /* Convert from RGB to HSV in scene linear space color for number editing. */ + if (cpicker->is_init == false) { + ui_color_picker_rgb_to_hsv(rgb_scene_linear, cpicker->hsv_scene_linear); + } + else { + ui_color_picker_rgb_to_hsv_compat(rgb_scene_linear, cpicker->hsv_scene_linear); + } + + /* Convert from RGB to HSV in perceptually linear space for picker widgets. */ + float rgb_perceptual[3]; + copy_v3_v3(rgb_perceptual, rgb_scene_linear); + if (from_but) { + ui_scene_linear_to_perceptual_space(from_but, rgb_perceptual); + } + + if (cpicker->is_init == false) { + ui_color_picker_rgb_to_hsv(rgb_perceptual, cpicker->hsv_perceptual); + copy_v3_v3(cpicker->hsv_perceptual_init, cpicker->hsv_perceptual); + } + else { + ui_color_picker_rgb_to_hsv_compat(rgb_perceptual, cpicker->hsv_perceptual); + } + + cpicker->is_init = true; +} + /* for picker, while editing hsv */ void ui_but_hsv_set(uiBut *but) { - float col[3]; + float rgb_perceptual[3]; ColorPicker *cpicker = but->custom_data; - float *hsv = cpicker->color_data; + float *hsv_perceptual = cpicker->hsv_perceptual; - ui_color_picker_to_rgb_v(hsv, col); + ui_color_picker_hsv_to_rgb(hsv_perceptual, rgb_perceptual); - ui_but_v3_set(but, col); + ui_but_v3_set(but, rgb_perceptual); } /* Updates all buttons who share the same color picker as the one passed @@ -180,17 +200,9 @@ void ui_but_hsv_set(uiBut *but) static void ui_update_color_picker_buts_rgb(uiBut *from_but, uiBlock *block, ColorPicker *cpicker, - const float rgb[3]) + const float rgb_scene_linear[3]) { - float *hsv = cpicker->color_data; - - /* Convert from RGB to HSV in perceptually linear space. */ - float tmp[3]; - copy_v3_v3(tmp, rgb); - if (from_but) { - ui_scene_linear_to_color_picker_space(from_but, tmp); - } - ui_rgb_to_color_picker_compat_v(tmp, hsv); + ui_color_picker_update_hsv(cpicker, from_but, rgb_scene_linear); /* this updates button strings, * is hackish... but button pointers are on stack of caller function */ @@ -200,7 +212,7 @@ static void ui_update_color_picker_buts_rgb(uiBut *from_but, } if (bt->rnaprop) { - ui_but_v3_set(bt, rgb); + ui_but_v3_set(bt, rgb_scene_linear); /* original button that created the color picker already does undo * push, so disable it on RNA buttons in the color picker block */ @@ -213,7 +225,7 @@ static void ui_update_color_picker_buts_rgb(uiBut *from_but, /* Hex code is assumed to be in sRGB space * (coming from other applications, web, etc) */ - copy_v3_v3(rgb_hex, rgb); + copy_v3_v3(rgb_hex, rgb_scene_linear); if (from_but && !ui_but_is_color_gamma(from_but)) { IMB_colormanagement_scene_linear_to_srgb_v3(rgb_hex); ui_color_picker_rgb_round(rgb_hex); @@ -226,25 +238,25 @@ static void ui_update_color_picker_buts_rgb(uiBut *from_but, } else if (bt->str[1] == ' ') { if (bt->str[0] == 'R') { - ui_but_value_set(bt, rgb[0]); + ui_but_value_set(bt, rgb_scene_linear[0]); } else if (bt->str[0] == 'G') { - ui_but_value_set(bt, rgb[1]); + ui_but_value_set(bt, rgb_scene_linear[1]); } else if (bt->str[0] == 'B') { - ui_but_value_set(bt, rgb[2]); + ui_but_value_set(bt, rgb_scene_linear[2]); } else if (bt->str[0] == 'H') { - ui_but_value_set(bt, hsv[0]); + ui_but_value_set(bt, cpicker->hsv_scene_linear[0]); } else if (bt->str[0] == 'S') { - ui_but_value_set(bt, hsv[1]); + ui_but_value_set(bt, cpicker->hsv_scene_linear[1]); } else if (bt->str[0] == 'V') { - ui_but_value_set(bt, hsv[2]); + ui_but_value_set(bt, cpicker->hsv_scene_linear[2]); } else if (bt->str[0] == 'L') { - ui_but_value_set(bt, hsv[2]); + ui_but_value_set(bt, cpicker->hsv_scene_linear[2]); } } @@ -252,17 +264,17 @@ static void ui_update_color_picker_buts_rgb(uiBut *from_but, } } -static void ui_colorpicker_rna_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg)) +static void ui_colorpicker_rgba_update_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg)) { uiBut *but = (uiBut *)bt1; uiPopupBlockHandle *popup = but->block->handle; PropertyRNA *prop = but->rnaprop; PointerRNA ptr = but->rnapoin; - float rgb[4]; + float rgb_scene_linear[4]; if (prop) { - RNA_property_float_get_array(&ptr, prop, rgb); - ui_update_color_picker_buts_rgb(but, but->block, but->custom_data, rgb); + RNA_property_float_get_array(&ptr, prop, rgb_scene_linear); + ui_update_color_picker_buts_rgb(but, but->block, but->custom_data, rgb_scene_linear); } if (popup) { @@ -270,20 +282,15 @@ static void ui_colorpicker_rna_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(a } } -static void ui_color_wheel_rna_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg)) +static void ui_colorpicker_hsv_update_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg)) { uiBut *but = (uiBut *)bt1; uiPopupBlockHandle *popup = but->block->handle; - float rgb[3]; + float rgb_scene_linear[3]; ColorPicker *cpicker = but->custom_data; - float *hsv = cpicker->color_data; - ui_color_picker_to_rgb_v(hsv, rgb); - - /* hsv is saved in perceptually linear space so convert back */ - ui_color_picker_to_scene_linear_space(but, rgb); - - ui_update_color_picker_buts_rgb(but, but->block, cpicker, rgb); + ui_color_picker_hsv_to_rgb(cpicker->hsv_scene_linear, rgb_scene_linear); + ui_update_color_picker_buts_rgb(but, but->block, cpicker, rgb_scene_linear); if (popup) { popup->menuretval = UI_RETURN_UPDATE; @@ -321,7 +328,7 @@ static void ui_popup_close_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg)) if (popup) { ColorPicker *cpicker = but->custom_data; BLI_assert(cpicker->is_init); - popup->menuretval = (equals_v3v3(cpicker->color_data, cpicker->color_data_init) ? + popup->menuretval = (equals_v3v3(cpicker->hsv_perceptual, cpicker->hsv_perceptual_init) ? UI_RETURN_CANCEL : UI_RETURN_OK); } @@ -331,12 +338,12 @@ static void ui_colorpicker_hide_reveal(uiBlock *block, enum ePickerType colormod { /* tag buttons */ LISTBASE_FOREACH (uiBut *, bt, &block->buttons) { - if ((bt->func == ui_colorpicker_rna_cb) && (bt->type == UI_BTYPE_NUM_SLIDER) && + if ((bt->func == ui_colorpicker_rgba_update_cb) && (bt->type == UI_BTYPE_NUM_SLIDER) && (bt->rnaindex != 3)) { /* RGB sliders (color circle and alpha are always shown) */ SET_FLAG_FROM_TEST(bt->flag, (colormode != PICKER_TYPE_RGB), UI_HIDDEN); } - else if (bt->func == ui_color_wheel_rna_cb) { + else if (bt->func == ui_colorpicker_hsv_update_cb) { /* HSV sliders */ SET_FLAG_FROM_TEST(bt->flag, (colormode != PICKER_TYPE_HSV), UI_HIDDEN); } @@ -386,7 +393,7 @@ static void ui_colorpicker_circle(uiBlock *block, 0.0, 0, TIP_("Color")); - UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL); + UI_but_func_set(bt, ui_colorpicker_rgba_update_cb, bt, NULL); bt->custom_data = cpicker; /* value */ @@ -408,7 +415,7 @@ static void ui_colorpicker_circle(uiBlock *block, 0, "Lightness"); hsv_but->gradient_type = UI_GRAD_L_ALT; - UI_but_func_set(&hsv_but->but, ui_colorpicker_rna_cb, &hsv_but->but, NULL); + UI_but_func_set(&hsv_but->but, ui_colorpicker_rgba_update_cb, &hsv_but->but, NULL); } else { hsv_but = (uiButHSVCube *)uiDefButR_prop(block, @@ -428,7 +435,7 @@ static void ui_colorpicker_circle(uiBlock *block, 0, TIP_("Value")); hsv_but->gradient_type = UI_GRAD_V_ALT; - UI_but_func_set(&hsv_but->but, ui_colorpicker_rna_cb, &hsv_but->but, NULL); + UI_but_func_set(&hsv_but->but, ui_colorpicker_rgba_update_cb, &hsv_but->but, NULL); } hsv_but->but.custom_data = cpicker; } @@ -461,7 +468,7 @@ static void ui_colorpicker_square(uiBlock *block, 0, TIP_("Color")); hsv_but->gradient_type = type; - UI_but_func_set(&hsv_but->but, ui_colorpicker_rna_cb, &hsv_but->but, NULL); + UI_but_func_set(&hsv_but->but, ui_colorpicker_rgba_update_cb, &hsv_but->but, NULL); hsv_but->but.custom_data = cpicker; /* value */ @@ -482,12 +489,15 @@ static void ui_colorpicker_square(uiBlock *block, 0, TIP_("Value")); hsv_but->gradient_type = type + 3; - UI_but_func_set(&hsv_but->but, ui_colorpicker_rna_cb, &hsv_but->but, NULL); + UI_but_func_set(&hsv_but->but, ui_colorpicker_rgba_update_cb, &hsv_but->but, NULL); hsv_but->but.custom_data = cpicker; } /* a HS circle, V slider, rgb/hsv/hex sliders */ -static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4], bool show_picker) +static void ui_block_colorpicker(uiBlock *block, + uiBut *from_but, + float rgba_scene_linear[4], + bool show_picker) { /* ePickerType */ static char colormode = 1; @@ -497,7 +507,6 @@ static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4], float softmin, softmax, hardmin, hardmax, step, precision; int yco; ColorPicker *cpicker = ui_block_colorpicker_create(block); - float *hsv = cpicker->color_data; PointerRNA *ptr = &from_but->rnapoin; PropertyRNA *prop = from_but->rnaprop; @@ -505,20 +514,13 @@ static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4], butwidth = width - 1.5f * UI_UNIT_X; /* sneaky way to check for alpha */ - rgba[3] = FLT_MAX; + rgba_scene_linear[3] = FLT_MAX; RNA_property_float_ui_range(ptr, prop, &softmin, &softmax, &step, &precision); RNA_property_float_range(ptr, prop, &hardmin, &hardmax); - RNA_property_float_get_array(ptr, prop, rgba); + RNA_property_float_get_array(ptr, prop, rgba_scene_linear); - float rgb_perceptual[3]; - copy_v3_v3(rgb_perceptual, rgba); - ui_scene_linear_to_color_picker_space(from_but, rgb_perceptual); - ui_rgb_to_color_picker_v(rgb_perceptual, hsv); - if (cpicker->is_init == false) { - copy_v3_v3(cpicker->color_data_init, cpicker->color_data); - cpicker->is_init = true; - } + ui_color_picker_update_hsv(cpicker, from_but, rgba_scene_linear); /* when the softmax isn't defined in the RNA, * using very large numbers causes sRGB/linear round trip to fail. */ @@ -639,7 +641,7 @@ static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4], 0, 3, TIP_("Red")); - UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL); + UI_but_func_set(bt, ui_colorpicker_rgba_update_cb, bt, NULL); bt->custom_data = cpicker; bt = uiDefButR_prop(block, UI_BTYPE_NUM_SLIDER, @@ -657,7 +659,7 @@ static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4], 0, 3, TIP_("Green")); - UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL); + UI_but_func_set(bt, ui_colorpicker_rgba_update_cb, bt, NULL); bt->custom_data = cpicker; bt = uiDefButR_prop(block, UI_BTYPE_NUM_SLIDER, @@ -675,7 +677,7 @@ static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4], 0, 3, TIP_("Blue")); - UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL); + UI_but_func_set(bt, ui_colorpicker_rgba_update_cb, bt, NULL); bt->custom_data = cpicker; /* Could use: @@ -693,14 +695,14 @@ static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4], yco, butwidth, UI_UNIT_Y, - hsv, + cpicker->hsv_scene_linear, 0.0, 1.0, 10, 3, TIP_("Hue")); UI_but_flag_disable(bt, UI_BUT_UNDO); - UI_but_func_set(bt, ui_color_wheel_rna_cb, bt, hsv); + UI_but_func_set(bt, ui_colorpicker_hsv_update_cb, bt, NULL); bt->custom_data = cpicker; bt = uiDefButF(block, UI_BTYPE_NUM_SLIDER, @@ -710,14 +712,14 @@ static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4], yco -= UI_UNIT_Y, butwidth, UI_UNIT_Y, - hsv + 1, + cpicker->hsv_scene_linear + 1, 0.0, 1.0, 10, 3, TIP_("Saturation")); UI_but_flag_disable(bt, UI_BUT_UNDO); - UI_but_func_set(bt, ui_color_wheel_rna_cb, bt, hsv); + UI_but_func_set(bt, ui_colorpicker_hsv_update_cb, bt, NULL); bt->custom_data = cpicker; if (U.color_picker_type == USER_CP_CIRCLE_HSL) { bt = uiDefButF(block, @@ -728,7 +730,7 @@ static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4], yco -= UI_UNIT_Y, butwidth, UI_UNIT_Y, - hsv + 2, + cpicker->hsv_scene_linear + 2, 0.0, 1.0, 10, @@ -744,7 +746,7 @@ static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4], yco -= UI_UNIT_Y, butwidth, UI_UNIT_Y, - hsv + 2, + cpicker->hsv_scene_linear + 2, 0.0, softmax, 10, @@ -754,12 +756,12 @@ static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4], UI_but_flag_disable(bt, UI_BUT_UNDO); bt->hardmax = hardmax; /* not common but rgb may be over 1.0 */ - UI_but_func_set(bt, ui_color_wheel_rna_cb, bt, hsv); + UI_but_func_set(bt, ui_colorpicker_hsv_update_cb, bt, NULL); bt->custom_data = cpicker; UI_block_align_end(block); - if (rgba[3] != FLT_MAX) { + if (rgba_scene_linear[3] != FLT_MAX) { bt = uiDefButR_prop(block, UI_BTYPE_NUM_SLIDER, 0, @@ -776,18 +778,18 @@ static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4], 0, 3, TIP_("Alpha")); - UI_but_func_set(bt, ui_colorpicker_rna_cb, bt, NULL); + UI_but_func_set(bt, ui_colorpicker_rgba_update_cb, bt, NULL); bt->custom_data = cpicker; } else { - rgba[3] = 1.0f; + rgba_scene_linear[3] = 1.0f; } /* Hex color is in sRGB space. */ float rgb_hex[3]; uchar rgb_hex_uchar[3]; - copy_v3_v3(rgb_hex, rgba); + copy_v3_v3(rgb_hex, rgba_scene_linear); if (!ui_but_is_color_gamma(from_but)) { IMB_colormanagement_scene_linear_to_srgb_v3(rgb_hex); @@ -850,21 +852,22 @@ static int ui_colorpicker_small_wheel_cb(const bContext *UNUSED(C), LISTBASE_FOREACH (uiBut *, but, &block->buttons) { if (but->type == UI_BTYPE_HSVCUBE && but->active == NULL) { uiPopupBlockHandle *popup = block->handle; - float rgb[3]; ColorPicker *cpicker = but->custom_data; - float *hsv = cpicker->color_data; + float *hsv_perceptual = cpicker->hsv_perceptual; - ui_but_v3_get(but, rgb); - ui_scene_linear_to_color_picker_space(but, rgb); - ui_rgb_to_color_picker_compat_v(rgb, hsv); + float rgb_perceptual[3]; + ui_but_v3_get(but, rgb_perceptual); + ui_scene_linear_to_perceptual_space(but, rgb_perceptual); + ui_color_picker_rgb_to_hsv_compat(rgb_perceptual, hsv_perceptual); - hsv[2] = clamp_f(hsv[2] + add, 0.0f, 1.0f); + hsv_perceptual[2] = clamp_f(hsv_perceptual[2] + add, 0.0f, 1.0f); - ui_color_picker_to_rgb_v(hsv, rgb); - ui_color_picker_to_scene_linear_space(but, rgb); - ui_but_v3_set(but, rgb); + float rgb_scene_linear[3]; + ui_color_picker_hsv_to_rgb(hsv_perceptual, rgb_scene_linear); + ui_perceptual_to_scene_linear_space(but, rgb_scene_linear); + ui_but_v3_set(but, rgb_scene_linear); - ui_update_color_picker_buts_rgb(but, block, cpicker, rgb); + ui_update_color_picker_buts_rgb(but, block, cpicker, rgb_scene_linear); if (popup) { popup->menuretval = UI_RETURN_UPDATE; } diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c index 12f3ba609f0..89515608c5b 100644 --- a/source/blender/editors/interface/interface_region_tooltip.c +++ b/source/blender/editors/interface/interface_region_tooltip.c @@ -534,7 +534,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is { uiStringInfo op_keymap = {BUT_GET_OP_KEYMAP, NULL}; - UI_but_string_info_get(C, but, &op_keymap, NULL); + UI_but_string_info_get(C, but, NULL, &op_keymap, NULL); shortcut = op_keymap.strinfo; } @@ -764,7 +764,9 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is return data; } -static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but) +static uiTooltipData *ui_tooltip_data_from_button(bContext *C, + uiBut *but, + uiButExtraOpIcon *extra_icon) { uiStringInfo but_label = {BUT_GET_LABEL, NULL}; uiStringInfo but_tip = {BUT_GET_TIP, NULL}; @@ -777,20 +779,29 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but) char buf[512]; + wmOperatorType *extra_icon_optype = UI_but_extra_operator_icon_optype_get(extra_icon); + wmOperatorType *optype = extra_icon ? extra_icon_optype : but->optype; + /* create tooltip data */ uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData"); - UI_but_string_info_get(C, - but, - &but_label, - &but_tip, - &enum_label, - &enum_tip, - &op_keymap, - &prop_keymap, - &rna_struct, - &rna_prop, - NULL); + if (extra_icon) { + UI_but_string_info_get(C, but, extra_icon, &but_label, &but_tip, &op_keymap, NULL); + } + else { + UI_but_string_info_get(C, + but, + NULL, + &but_label, + &but_tip, + &enum_label, + &enum_tip, + &op_keymap, + &prop_keymap, + &rna_struct, + &rna_prop, + NULL); + } /* Tip Label (only for buttons not already showing the label). * Check prefix instead of comparing because the button may include the shortcut. */ @@ -923,15 +934,16 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but) } } } - else if (but->optype) { - PointerRNA *opptr; - char *str; - opptr = UI_but_operator_ptr_get(but); /* allocated when needed, the button owns it */ + else if (optype) { + PointerRNA *opptr = extra_icon_optype ? + UI_but_extra_operator_icon_opptr_get(extra_icon) : + UI_but_operator_ptr_get( + but); /* allocated when needed, the button owns it */ /* so the context is passed to fieldf functions (some py fieldf functions use it) */ WM_operator_properties_sanitize(opptr, false); - str = ui_tooltip_text_python_from_op(C, but->optype, opptr); + char *str = ui_tooltip_text_python_from_op(C, optype, opptr); /* operator info */ if (U.flag & USER_TOOLTIPS_PYTHON) { @@ -958,7 +970,7 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but) disabled_msg = CTX_wm_operator_poll_msg_get(C); } /* alternatively, buttons can store some reasoning too */ - else if (but->disabled_info) { + if (!disabled_msg && but->disabled_info) { disabled_msg = TIP_(but->disabled_info); } @@ -1398,11 +1410,8 @@ static ARegion *ui_tooltip_create_with_data(bContext *C, /** \name ToolTip Public API * \{ */ -/** - * \param is_label: When true, show a small tip that only shows the name, - * otherwise show the full tooltip. - */ -ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *but, bool is_label) +ARegion *UI_tooltip_create_from_button_or_extra_icon( + bContext *C, ARegion *butregion, uiBut *but, uiButExtraOpIcon *extra_icon, bool is_label) { wmWindow *win = CTX_wm_window(C); /* aspect values that shrink text are likely unreadable */ @@ -1419,7 +1428,7 @@ ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *b } if (data == NULL) { - data = ui_tooltip_data_from_button(C, but); + data = ui_tooltip_data_from_button(C, but, extra_icon); } if (data == NULL) { @@ -1457,6 +1466,15 @@ ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *b return region; } +/** + * \param is_label: When true, show a small tip that only shows the name, + * otherwise show the full tooltip. + */ +ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *but, bool is_label) +{ + return UI_tooltip_create_from_button_or_extra_icon(C, butregion, but, NULL, is_label); +} + ARegion *UI_tooltip_create_from_gizmo(bContext *C, wmGizmo *gz) { wmWindow *win = CTX_wm_window(C); diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c index c3d528ad5c5..a37fb0dfde1 100644 --- a/source/blender/editors/interface/interface_style.c +++ b/source/blender/editors/interface/interface_style.c @@ -206,8 +206,12 @@ void UI_fontstyle_draw_ex(const uiFontStyle *fs, BLF_disable(fs->uifont_id, font_flag); - *r_xofs = xofs; - *r_yofs = yofs; + if (r_xofs) { + *r_xofs = xofs; + } + if (r_yofs) { + *r_yofs = yofs; + } } void UI_fontstyle_draw(const uiFontStyle *fs, diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 43ead511cfe..404ae0df6a1 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -102,9 +102,16 @@ // #define USE_OP_RESET_BUT /* defines for templateID/TemplateSearch */ -#define TEMPLATE_SEARCH_TEXTBUT_WIDTH (UI_UNIT_X * 6) +#define TEMPLATE_SEARCH_TEXTBUT_WIDTH (UI_UNIT_X * 8) #define TEMPLATE_SEARCH_TEXTBUT_HEIGHT UI_UNIT_Y +/* Add "Make Single User" button to templateID. Users can just manually duplicate an ID, it's + * unclear what the use-case of this specific button is. So for now disabling it, we can bring it + * back or remove it later. + * - Julian + */ +//#define USE_TEMPLATE_ID_MAKE_SINGLE_USER + void UI_template_fix_linking(void) { } @@ -308,6 +315,12 @@ typedef struct TemplateID { ListBase *idlb; short idcode; + + const char *new_op; + const char *duplicate_op; + const char *unlink_op; + const char *open_op; + short filter; int prv_rows, prv_cols; bool preview; @@ -564,80 +577,64 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) memset(&idptr, 0, sizeof(idptr)); RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, NULL); RNA_property_update(C, &template_ui->ptr, template_ui->prop); - - if (id && CTX_wm_window(C)->eventstate->shift) { - /* only way to force-remove data (on save) */ - id_us_clear_real(id); - id_fake_user_clear(id); - id->us = 0; - undo_push_label = "Delete Data-Block"; - } - break; - case UI_ID_FAKE_USER: + case UI_ID_MAKE_LOCAL: if (id) { - if (id->flag & LIB_FAKEUSER) { - id_us_plus(id); - } - else { - id_us_min(id); + Main *bmain = CTX_data_main(C); + if (BKE_lib_id_make_local(bmain, id, false, 0)) { + BKE_main_id_clear_newpoins(bmain); + + /* reassign to get get proper updates/notifiers */ + idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop); + RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, NULL); + RNA_property_update(C, &template_ui->ptr, template_ui->prop); + undo_push_label = "Make Local"; } - undo_push_label = "Fake User"; - } - else { - return; } break; - case UI_ID_LOCAL: - if (id) { + case UI_ID_LIB_OVERRIDE_ADD: + if (id && ID_IS_OVERRIDABLE_LIBRARY(id)) { Main *bmain = CTX_data_main(C); - if (CTX_wm_window(C)->eventstate->shift) { - if (ID_IS_OVERRIDABLE_LIBRARY(id)) { - /* Only remap that specific ID usage to overriding local data-block. */ - ID *override_id = BKE_lib_override_library_create_from_id(bmain, id, false); - if (override_id != NULL) { - BKE_main_id_clear_newpoins(bmain); - - if (GS(override_id->name) == ID_OB) { - Scene *scene = CTX_data_scene(C); - if (!BKE_collection_has_object_recursive(scene->master_collection, - (Object *)override_id)) { - BKE_collection_object_add_from( - bmain, scene, (Object *)id, (Object *)override_id); - } - } - - /* Assign new pointer, takes care of updates/notifiers */ - RNA_id_pointer_create(override_id, &idptr); + /* Only remap that specific ID usage to overriding local data-block. */ + ID *override_id = BKE_lib_override_library_create_from_id(bmain, id, false); + if (override_id != NULL) { + BKE_main_id_clear_newpoins(bmain); + + if (GS(override_id->name) == ID_OB) { + Scene *scene = CTX_data_scene(C); + if (!BKE_collection_has_object_recursive(scene->master_collection, + (Object *)override_id)) { + BKE_collection_object_add_from(bmain, scene, (Object *)id, (Object *)override_id); } - undo_push_label = "Make Library Override"; } - } - else { - if (BKE_lib_id_make_local(bmain, id, false, 0)) { - BKE_main_id_clear_newpoins(bmain); - /* reassign to get get proper updates/notifiers */ - idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop); - undo_push_label = "Make Local"; - } - } - if (undo_push_label != NULL) { - RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, NULL); - RNA_property_update(C, &template_ui->ptr, template_ui->prop); + /* Assign new pointer, takes care of updates/notifiers */ + RNA_id_pointer_create(override_id, &idptr); } + /* reassign to get get proper updates/notifiers */ + RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, NULL); + RNA_property_update(C, &template_ui->ptr, template_ui->prop); + undo_push_label = "Make Library Override"; } break; - case UI_ID_OVERRIDE: + case UI_ID_LIB_OVERRIDE_RESET: + if (id && ID_IS_OVERRIDE_LIBRARY_REAL(id)) { + Main *bmain = CTX_data_main(C); + BKE_lib_override_library_id_reset(bmain, id); + undo_push_label = "Reset Library Override"; + } + break; + case UI_ID_LIB_OVERRIDE_REMOVE: if (id && ID_IS_OVERRIDE_LIBRARY(id)) { BKE_lib_override_library_free(&id->override_library, true); /* reassign to get get proper updates/notifiers */ idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop); RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, NULL); RNA_property_update(C, &template_ui->ptr, template_ui->prop); - undo_push_label = "Override Data-Block"; + undo_push_label = "Remove Library Override"; } break; +#ifdef USE_TEMPLATE_ID_MAKE_SINGLE_USER case UI_ID_ALONE: if (id) { const bool do_scene_obj = ((GS(id->name) == ID_OB) && @@ -659,6 +656,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) undo_push_label = "Make Single User"; } break; +#endif #if 0 case UI_ID_AUTO_NAME: break; @@ -772,17 +770,221 @@ static const char *template_id_context(StructRNA *type) # define template_id_context(type) 0 #endif -static uiBut *template_id_def_new_but(uiBlock *block, - const ID *id, - const TemplateID *template_ui, - StructRNA *type, - const char *const newop, - const bool editable, - const bool id_open, - const bool use_tab_but, - int but_height) -{ +static void template_id_linked_operation_button( + uiBlock *block, Main *bmain, ID *id, TemplateID *template_ui, int operation) +{ + BLI_assert(ELEM(operation, UI_ID_MAKE_LOCAL, UI_ID_LIB_OVERRIDE_ADD)); + + const char *label = (operation == UI_ID_MAKE_LOCAL) ? + CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Make Local") : + CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Library Override"); + const char *tip = (operation == UI_ID_MAKE_LOCAL) ? + N_("Make library linked data-block local to this file") : + N_("Create a local override of this library linked data-block"); + BIFIconID icon = (operation == UI_ID_MAKE_LOCAL) ? ICON_BLANK1 : ICON_LIBRARY_DATA_OVERRIDE; + + uiBut *but = uiDefIconTextBut(block, + UI_BTYPE_BUT, + 0, + icon, + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, label), + 0, + 0, + UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0, + 0, + 0, + 0, + TIP_(tip)); + + bool disabled = false; + + if (!ID_IS_LINKED(id)) { + disabled = true; + but->disabled_info = TIP_("Data-block is not linked"); + } + else if (id->tag & LIB_TAG_INDIRECT) { + disabled = true; + but->disabled_info = TIP_("Indirect library data-block, cannot change"); + } + else if (!BKE_lib_id_make_local(bmain, id, true /* test */, 0)) { + disabled = true; + but->disabled_info = TIP_("Data-blocks of this type cannot be made local"); + } + else if (!RNA_property_editable_info( + &template_ui->ptr, template_ui->prop, &but->disabled_info)) { + disabled = true; + } + + if (disabled) { + UI_but_flag_enable(but, UI_BUT_DISABLED); + } + else { + UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(operation)); + } +} + +static void template_id_library_overridden_button(uiBlock *block, + ID *id, + TemplateID *template_ui, + int operation) +{ + BLI_assert(ELEM(operation, UI_ID_LIB_OVERRIDE_RESET, UI_ID_LIB_OVERRIDE_REMOVE) && + ID_IS_OVERRIDE_LIBRARY(id)); + + if (operation == UI_ID_LIB_OVERRIDE_RESET && ID_IS_OVERRIDE_LIBRARY_REAL(id)) { + uiBut *but = uiDefIconTextBut( + block, + UI_BTYPE_BUT, + 0, + ICON_BLANK1, + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Reset Library Override"), + 0, + 0, + UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0, + 0, + 0, + 0, + TIP_("Reset the local override to the state of " + "the overridden data-block")); + if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) { + but->disabled_info = TIP_("Data-block is a virtual, not a real override"); + UI_but_flag_enable(but, UI_BUT_DISABLED); + } + else { + UI_but_funcN_set(but, + template_id_cb, + MEM_dupallocN(template_ui), + POINTER_FROM_INT(UI_ID_LIB_OVERRIDE_RESET)); + } + } + else if (operation == UI_ID_LIB_OVERRIDE_REMOVE) { + uiBut *but = uiDefIconTextBut( + block, + UI_BTYPE_BUT, + 0, + ICON_BLANK1, + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Make Local"), + 0, + 0, + UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0, + 0, + 0, + 0, + TIP_("Remove library override and make the library linked data-block " + "fully local to this file")); + UI_but_funcN_set(but, + template_id_cb, + MEM_dupallocN(template_ui), + POINTER_FROM_INT(UI_ID_LIB_OVERRIDE_REMOVE)); + } +} + +#ifdef USE_TEMPLATE_ID_MAKE_SINGLE_USER +static uiBut *template_id_make_single_user_button(uiBlock *block, ID *id, TemplateID *template_ui) +{ + uiBut *but = uiDefIconTextBut( + block, + UI_BTYPE_BUT, + 0, + ICON_BLANK1, + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Make Single-User Copy"), + 0, + 0, + UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0, + 0, + 0, + 0, + TIP_("Duplicate the data-block and assign the newly created copy")); + + if (ID_REAL_USERS(id) <= 1) { + UI_but_flag_enable(but, UI_BUT_DISABLED); + but->disabled_info = TIP_("Data-block already is a single-user"); + /* No need for further setup. */ + return but; + } + + UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_ALONE)); + ID *idfrom = template_ui->ptr.owner_id; + bool disabled = false; + + if (!RNA_property_editable_info(&template_ui->ptr, template_ui->prop, &but->disabled_info)) { + disabled = true; + } + if (!BKE_id_copy_is_allowed(id)) { + but->disabled_info = TIP_("Data-blocks of this type cannot be copied"); + disabled = true; + } + /* object in editmode - don't change data */ + if (idfrom && GS(idfrom->name) == ID_OB && (((Object *)idfrom)->mode & OB_MODE_EDIT)) { + but->disabled_info = TIP_("Cannot change object data in Edit Mode"); + disabled = true; + } + + if (disabled) { + UI_but_flag_enable(but, UI_BUT_DISABLED); + } + + return but; +} +#endif + +static void template_id_use_fake_user_button(uiBlock *block, PointerRNA *idptr) +{ + const bool use_fake_user = ID_FAKE_USERS(idptr->data) > 0; + uiBut *but = uiDefIconTextButR( + block, + UI_BTYPE_ICON_TOGGLE, + 0, + ICON_FAKE_USER_OFF, + use_fake_user ? CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Fake User") : + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Fake User"), + 0, + 0, + UI_UNIT_X, + UI_UNIT_Y, + idptr, + "use_fake_user", + -1, + 0, + 0, + -1, + -1, + TIP_("When set, ensures the data-block is kept when reloading the file, even if not used at " + "all")); + + if ((ELEM(GS(((ID *)idptr->data)->name), ID_GR, ID_SCE, ID_SCR, ID_TXT, ID_OB, ID_WS))) { + but->disabled_info = TIP_("Data-block type does not support fake user"); + UI_but_flag_enable(but, UI_BUT_DISABLED); + } +} + +enum TemplateIDCreateType { + TEMPLATE_ID_CREATE_NEW, + TEMPLATE_ID_CREATE_DUPLICATE, +}; + +static uiBut *template_id_new_button(uiBlock *block, + const ID *id, + TemplateID *template_ui, + enum TemplateIDCreateType create_type, + StructRNA *type, + const bool id_open, + const bool use_tab_but, + int but_height) +{ uiBut *but; const int w = id ? UI_UNIT_X : id_open ? UI_UNIT_X * 3 : UI_UNIT_X * 6; const int but_type = use_tab_but ? UI_BTYPE_TAB : UI_BTYPE_BUT; @@ -820,54 +1022,384 @@ static uiBut *template_id_def_new_but(uiBlock *block, BLT_I18NCONTEXT_ID_POINTCLOUD, BLT_I18NCONTEXT_ID_VOLUME, BLT_I18NCONTEXT_ID_SIMULATION, ); + BLT_I18N_MSGID_MULTI_CTXT("Duplicate", + BLT_I18NCONTEXT_DEFAULT, + BLT_I18NCONTEXT_ID_SCENE, + BLT_I18NCONTEXT_ID_OBJECT, + BLT_I18NCONTEXT_ID_MESH, + BLT_I18NCONTEXT_ID_CURVE, + BLT_I18NCONTEXT_ID_METABALL, + BLT_I18NCONTEXT_ID_MATERIAL, + BLT_I18NCONTEXT_ID_TEXTURE, + BLT_I18NCONTEXT_ID_IMAGE, + BLT_I18NCONTEXT_ID_LATTICE, + BLT_I18NCONTEXT_ID_LIGHT, + BLT_I18NCONTEXT_ID_CAMERA, + BLT_I18NCONTEXT_ID_WORLD, + BLT_I18NCONTEXT_ID_SCREEN, + BLT_I18NCONTEXT_ID_TEXT, ); + BLT_I18N_MSGID_MULTI_CTXT("Duplicate", + BLT_I18NCONTEXT_ID_SPEAKER, + BLT_I18NCONTEXT_ID_SOUND, + BLT_I18NCONTEXT_ID_ARMATURE, + BLT_I18NCONTEXT_ID_ACTION, + BLT_I18NCONTEXT_ID_NODETREE, + BLT_I18NCONTEXT_ID_BRUSH, + BLT_I18NCONTEXT_ID_PARTICLESETTINGS, + BLT_I18NCONTEXT_ID_GPENCIL, + BLT_I18NCONTEXT_ID_FREESTYLELINESTYLE, + BLT_I18NCONTEXT_ID_WORKSPACE, + BLT_I18NCONTEXT_ID_LIGHTPROBE, + BLT_I18NCONTEXT_ID_HAIR, + BLT_I18NCONTEXT_ID_POINTCLOUD, + BLT_I18NCONTEXT_ID_VOLUME, + BLT_I18NCONTEXT_ID_SIMULATION, ); /* Note: BLT_I18N_MSGID_MULTI_CTXT takes a maximum number of parameters, * check the definition to see if a new call must be added when the limit * is exceeded. */ - if (newop) { + const char *text; + const char *op; + BIFIconID icon; + + switch (create_type) { + case TEMPLATE_ID_CREATE_NEW: + icon = ICON_ADD; + text = CTX_IFACE_(template_id_context(type), "New"); + op = template_ui->new_op; + break; + case TEMPLATE_ID_CREATE_DUPLICATE: + icon = ICON_DUPLICATE; + text = CTX_IFACE_(template_id_context(type), "Duplicate"); + op = template_ui->duplicate_op; + break; + } + + const bool icon_only = use_tab_but; + if (icon_only) { + text = ""; + } + + if (op) { + but = uiDefIconTextButO( + block, but_type, op, WM_OP_INVOKE_DEFAULT, icon, text, 0, 0, w, but_height, NULL); + UI_but_funcN_set( + but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_ADD_NEW)); + + if (!RNA_property_editable_info(&template_ui->ptr, template_ui->prop, &but->disabled_info)) { + UI_but_flag_enable(but, UI_BUT_DISABLED); + } + } + else { + but = uiDefIconTextBut(block, + but_type, + 0, + icon, + text, + 0, + 0, + w, + but_height, + NULL, + 0, + 0, + 0, + 0, + TIP_("Create a new data-block")); + but->disabled_info = TIP_("Creating a new data-block is not supported here"); + UI_but_flag_enable(but, UI_BUT_DISABLED); + } + if (icon_only) { + UI_but_drawflag_disable(but, UI_BUT_ICON_LEFT); + } + +#ifndef WITH_INTERNATIONAL + UNUSED_VARS(type); +#endif + + return but; +} + +static void template_id_unlink_button(uiBlock *block, + TemplateID *template_ui, + bool hide_if_disabled) +{ + const char *disable_info; + const bool is_menu = ui_block_is_menu(block); + const bool editable = RNA_property_editable_info( + &template_ui->ptr, template_ui->prop, &disable_info); + /* allow unlink if 'unlinkop' is passed, even when 'PROP_NEVER_UNLINK' is set */ + uiBut *but = NULL; + + if (hide_if_disabled && !editable) { + /* Add no button. */ + } + else if (template_ui->unlink_op) { but = uiDefIconTextButO(block, - but_type, - newop, + UI_BTYPE_BUT, + template_ui->unlink_op, WM_OP_INVOKE_DEFAULT, - (id && !use_tab_but) ? ICON_DUPLICATE : ICON_ADD, - (id) ? "" : CTX_IFACE_(template_id_context(type), "New"), + ICON_X, + is_menu ? NULL : "", + 0, + 0, + UI_UNIT_X, + UI_UNIT_Y, + NULL); + /* so we can access the template from operators, font unlinking needs this */ + UI_but_funcN_set(but, NULL, MEM_dupallocN(template_ui), NULL); + } + else { + const bool never_unlink = RNA_property_flag(template_ui->prop) & + (PROP_NEVER_UNLINK | PROP_NEVER_NULL); + + if (!never_unlink || !hide_if_disabled) { + but = uiDefIconTextBut(block, + UI_BTYPE_BUT, + 0, + ICON_X, + is_menu ? CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Unlink") : "", + 0, + 0, + UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0, + 0, + 0, + 0, + TIP_("Remove this usage of the data-block")); + if (!never_unlink) { + UI_but_funcN_set( + but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_DELETE)); + } + if (!is_menu) { + UI_but_drawflag_disable(but, UI_BUT_ICON_LEFT); + } + } + + if (but && never_unlink) { + but->disabled_info = TIP_("Property must never be in an unlinked state"); + UI_but_flag_enable(but, UI_BUT_DISABLED); + } + } + + if (but) { + if (!editable) { + but->disabled_info = disable_info; + UI_but_flag_enable(but, UI_BUT_DISABLED); + } + } +} + +static void template_id_open_button(uiBlock *block, + ID *id, + TemplateID *template_ui, + const bool compact) +{ + const bool is_menu = ui_block_is_menu(block); + const int w = compact ? UI_UNIT_X * 3 : UI_UNIT_X * 6; + char text[UI_MAX_NAME_STR] = ""; + const bool icon_only = !is_menu && id; + uiBut *but; + + if (!icon_only) { + BLI_snprintf(text, + sizeof(text), + "%s%s", + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Open"), + is_menu ? "..." : ""); + } + + if (template_ui->open_op) { + but = uiDefIconTextButO(block, + UI_BTYPE_BUT, + template_ui->open_op, + WM_OP_INVOKE_DEFAULT, + ICON_FILEBROWSER, + text, 0, 0, w, - but_height, + UI_UNIT_Y, NULL); UI_but_funcN_set( - but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_ADD_NEW)); + but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_OPEN)); } else { but = uiDefIconTextBut(block, - but_type, + UI_BTYPE_BUT, 0, - (id && !use_tab_but) ? ICON_DUPLICATE : ICON_ADD, - (id) ? "" : CTX_IFACE_(template_id_context(type), "New"), + ICON_FILEBROWSER, + text, 0, 0, w, - but_height, + UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL); - UI_but_funcN_set( - but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_ADD_NEW)); + but->disabled_info = TIP_("Browsing for a new data-block is not supported here"); + UI_but_flag_enable(but, UI_BUT_DISABLED); } - if ((idfrom && idfrom->lib) || !editable) { + if (!RNA_property_editable_info(&template_ui->ptr, template_ui->prop, &but->disabled_info)) { UI_but_flag_enable(but, UI_BUT_DISABLED); } +} -#ifndef WITH_INTERNATIONAL - UNUSED_VARS(type); +static void template_id_unpack_button(uiBlock *block, ID *id) +{ + wmOperatorType *optype = WM_operatortype_find("FILE_OT_unpack_item", false); + uiBut *but; + + but = uiDefIconTextButO_ptr(block, + UI_BTYPE_BUT, + optype, + WM_OP_INVOKE_REGION_WIN, + ICON_PACKAGE, + NULL, + 0, + 0, + UI_UNIT_X, + UI_UNIT_Y, + NULL); + + if (!BKE_packedfile_id_check(id)) { + but->disabled_info = TIP_("File is not packed"); + UI_but_flag_enable(but, UI_BUT_DISABLED); + } + UI_but_operator_ptr_get(but); + + RNA_string_set(but->opptr, "id_name", id->name + 2); + RNA_int_set(but->opptr, "id_type", GS(id->name)); +} + +static void template_id_user_count_label(uiLayout *layout, const ID *id) +{ + char numstr[UI_MAX_NAME_STR]; + BLI_snprintf(numstr, + sizeof(numstr), + "%d %s", + ID_REAL_USERS(id), + ID_REAL_USERS(id) > 1 ? IFACE_("Users") : IFACE_("User")); + uiItemL(layout, numstr, ICON_NONE); +} + +static void template_id_menu(bContext *C, uiLayout *layout, void *arg) +{ + /* Button that spawned the menu. */ + const uiBut *menu_parent_but = arg; + TemplateID *template_ui = menu_parent_but->func_argN; + PointerRNA idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop); + ID *id = idptr.data; + uiBlock *block = uiLayoutGetBlock(layout); + + BLI_assert(id); + + template_id_new_button( + block, id, template_ui, TEMPLATE_ID_CREATE_NEW, idptr.type, false, false, UI_UNIT_X); + template_id_new_button( + block, id, template_ui, TEMPLATE_ID_CREATE_DUPLICATE, idptr.type, false, false, UI_UNIT_X); + template_id_unlink_button(block, template_ui, false); + +#ifdef USE_TEMPLATE_ID_MAKE_SINGLE_USER + template_id_make_single_user_button(block, id, template_ui); #endif + template_id_use_fake_user_button(block, &idptr); - return but; + if (template_ui->open_op || BKE_packedfile_id_check(id)) { + uiItemS(layout); + + template_id_open_button(block, id, template_ui, false); + template_id_unpack_button(block, id); + } + + /* Library operators. */ + if (ID_IS_OVERRIDE_LIBRARY(id)) { + uiItemS(layout); + + template_id_library_overridden_button(block, id, template_ui, UI_ID_LIB_OVERRIDE_RESET); + template_id_library_overridden_button(block, id, template_ui, UI_ID_LIB_OVERRIDE_REMOVE); + } + else if (ID_IS_LINKED(id)) { + uiItemS(layout); + + Main *bmain = CTX_data_main(C); + template_id_linked_operation_button(block, bmain, id, template_ui, UI_ID_MAKE_LOCAL); + template_id_linked_operation_button(block, bmain, id, template_ui, UI_ID_LIB_OVERRIDE_ADD); + } + + uiItemS(layout); + template_id_user_count_label(layout, id); +} + +static void template_id_name_button( + uiBlock *block, StructRNA *type, TemplateID *template_ui, int flag, const bool hide_extras) +{ + PointerRNA idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop); + ID *id = idptr.data; + BIFIconID lib_icon = UI_icon_from_library(id); + + char name[UI_MAX_NAME_STR] = ""; + uiBut *but = uiDefIconTextButR(block, + UI_BTYPE_TEXT, + 0, + lib_icon, + name, + 0, + 0, + TEMPLATE_SEARCH_TEXTBUT_WIDTH, + TEMPLATE_SEARCH_TEXTBUT_HEIGHT, + &idptr, + "name", + -1, + 0, + 0, + 0, + 0, + RNA_struct_ui_description(type)); + /* Note: Also needed for the extra icons below (their operators access the TemplateID). */ + UI_but_funcN_set( + but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_RENAME)); + + const bool user_alert = (id->us <= 0); + if (user_alert) { + UI_but_flag_enable(but, UI_BUT_REDALERT); + } + + if (hide_extras) { + return; + } + + if (template_ui->duplicate_op && (flag & UI_ID_ADD_NEW)) { + UI_but_extra_operator_icon_add( + but, template_ui->duplicate_op, WM_OP_INVOKE_DEFAULT, ICON_DUPLICATE); + } + + if (id && (flag & UI_ID_DELETE)) { + const bool never_unlink = RNA_property_flag(template_ui->prop) & + (PROP_NEVER_UNLINK | PROP_NEVER_NULL); + if (template_ui->unlink_op) { + UI_but_extra_operator_icon_add(but, template_ui->unlink_op, WM_OP_INVOKE_DEFAULT, ICON_X); + } + else if (!never_unlink) { + UI_but_extra_operator_icon_add(but, "ED_OT_lib_unlink", WM_OP_INVOKE_DEFAULT, ICON_X); + } + } + + /* Disable fake user icon for now, only have it in the menu. */ + const bool add_extra_fake_user_icon = false; + if (add_extra_fake_user_icon && id->lib == NULL && + !(ELEM(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_TXT, ID_OB, ID_WS))) { + UI_but_extra_operator_icon_add(but, + "ED_OT_lib_fake_user_toggle", + WM_OP_INVOKE_DEFAULT, + ID_FAKE_USERS(id) ? ICON_FAKE_USER_ON : ICON_FAKE_USER_OFF); + } } static void template_ID(const bContext *C, @@ -875,9 +1407,6 @@ static void template_ID(const bContext *C, TemplateID *template_ui, StructRNA *type, int flag, - const char *newop, - const char *openop, - const char *unlinkop, const char *text, const bool live_icon, const bool hide_buttons) @@ -885,15 +1414,15 @@ static void template_ID(const bContext *C, uiBut *but; uiBlock *block; PointerRNA idptr; - // ListBase *lb; // UNUSED - ID *id, *idfrom; + ID *id; const bool editable = RNA_property_editable(&template_ui->ptr, template_ui->prop); const bool use_previews = template_ui->preview = (flag & UI_ID_PREVIEWS) != 0; idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop); id = idptr.data; - idfrom = template_ui->ptr.owner_id; - // lb = template_ui->idlb; + + /* Allow opertators to take the ID from context. */ + uiLayoutSetContextPointer(layout, "id", &idptr); block = uiLayoutGetBlock(layout); UI_block_align_begin(block); @@ -923,277 +1452,39 @@ static void template_ID(const bContext *C, /* text button with name */ if (id) { - char name[UI_MAX_NAME_STR]; - const bool user_alert = (id->us <= 0); - - // text_idbutton(id, name); - name[0] = '\0'; - but = uiDefButR(block, - UI_BTYPE_TEXT, - 0, - name, - 0, - 0, - TEMPLATE_SEARCH_TEXTBUT_WIDTH, - TEMPLATE_SEARCH_TEXTBUT_HEIGHT, - &idptr, - "name", - -1, - 0, - 0, - -1, - -1, - RNA_struct_ui_description(type)); - UI_but_funcN_set( - but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_RENAME)); - if (user_alert) { - UI_but_flag_enable(but, UI_BUT_REDALERT); - } - - if (id->lib) { - if (id->tag & LIB_TAG_INDIRECT) { - but = uiDefIconBut(block, - UI_BTYPE_BUT, - 0, - ICON_LIBRARY_DATA_INDIRECT, - 0, - 0, - UI_UNIT_X, - UI_UNIT_Y, - NULL, - 0, - 0, - 0, - 0, - TIP_("Indirect library data-block, cannot change")); - UI_but_flag_enable(but, UI_BUT_DISABLED); - } - else { - const bool disabled = (!BKE_lib_id_make_local(CTX_data_main(C), id, true /* test */, 0) || - (idfrom && idfrom->lib)); - but = uiDefIconBut(block, - UI_BTYPE_BUT, - 0, - ICON_LIBRARY_DATA_DIRECT, - 0, - 0, - UI_UNIT_X, - UI_UNIT_Y, - NULL, - 0, - 0, - 0, - 0, - TIP_("Direct linked library data-block, click to make local, " - "Shift + Click to create a library override")); - if (disabled) { - UI_but_flag_enable(but, UI_BUT_DISABLED); - } - else { - UI_but_funcN_set( - but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_LOCAL)); - } - } - } - else if (ID_IS_OVERRIDE_LIBRARY(id)) { - but = uiDefIconBut(block, - UI_BTYPE_BUT, - 0, - ICON_LIBRARY_DATA_OVERRIDE, - 0, - 0, - UI_UNIT_X, - UI_UNIT_Y, - NULL, - 0, - 0, - 0, - 0, - TIP_("Library override of linked data-block, click to make fully local")); - UI_but_funcN_set( - but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_OVERRIDE)); - } - - if ((ID_REAL_USERS(id) > 1) && (hide_buttons == false)) { - char numstr[32]; - short numstr_len; - - numstr_len = BLI_snprintf(numstr, sizeof(numstr), "%d", ID_REAL_USERS(id)); - - but = uiDefBut( - block, - UI_BTYPE_BUT, - 0, - numstr, - 0, - 0, - numstr_len * 0.2f * UI_UNIT_X + UI_UNIT_X, - UI_UNIT_Y, - NULL, - 0, - 0, - 0, - 0, - TIP_("Display number of users of this data (click to make a single-user copy)")); - but->flag |= UI_BUT_UNDO; - - UI_but_funcN_set( - but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_ALONE)); - if ((!BKE_id_copy_is_allowed(id)) || (idfrom && idfrom->lib) || (!editable) || - /* object in editmode - don't change data */ - (idfrom && GS(idfrom->name) == ID_OB && (((Object *)idfrom)->mode & OB_MODE_EDIT))) { - UI_but_flag_enable(but, UI_BUT_DISABLED); - } - } - - if (user_alert) { - UI_but_flag_enable(but, UI_BUT_REDALERT); - } - - if (id->lib == NULL && !(ELEM(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_TXT, ID_OB, ID_WS)) && - (hide_buttons == false)) { - uiDefIconButR(block, - UI_BTYPE_ICON_TOGGLE, - 0, - ICON_FAKE_USER_OFF, - 0, - 0, - UI_UNIT_X, - UI_UNIT_Y, - &idptr, - "use_fake_user", - -1, - 0, - 0, - -1, - -1, - NULL); - } + template_id_name_button(block, type, template_ui, flag, hide_buttons); } - - if ((flag & UI_ID_ADD_NEW) && (hide_buttons == false)) { - template_id_def_new_but( - block, id, template_ui, type, newop, editable, flag & UI_ID_OPEN, false, UI_UNIT_X); + /* If no ID is set, show a "new" button instead of a text button. */ + else if ((flag & UI_ID_ADD_NEW) && (hide_buttons == false)) { + template_id_new_button( + block, id, template_ui, TEMPLATE_ID_CREATE_NEW, type, flag & UI_ID_OPEN, false, UI_UNIT_X); } - /* Due to space limit in UI - skip the "open" icon for packed data, and allow to unpack. - * Only for images, sound and fonts */ - if (id && BKE_packedfile_id_check(id)) { - but = uiDefIconButO(block, - UI_BTYPE_BUT, - "FILE_OT_unpack_item", - WM_OP_INVOKE_REGION_WIN, - ICON_PACKAGE, - 0, - 0, - UI_UNIT_X, - UI_UNIT_Y, - TIP_("Packed File, click to unpack")); - UI_but_operator_ptr_get(but); - - RNA_string_set(but->opptr, "id_name", id->name + 2); - RNA_int_set(but->opptr, "id_type", GS(id->name)); + if ((flag & UI_ID_OPEN) && !id) { + template_id_open_button(block, id, template_ui, flag & UI_ID_ADD_NEW); } - else if (flag & UI_ID_OPEN) { - const int w = id ? UI_UNIT_X : (flag & UI_ID_ADD_NEW) ? UI_UNIT_X * 3 : UI_UNIT_X * 6; - - if (openop) { - but = uiDefIconTextButO(block, - UI_BTYPE_BUT, - openop, - WM_OP_INVOKE_DEFAULT, - ICON_FILEBROWSER, - (id) ? "" : IFACE_("Open"), - 0, - 0, - w, - UI_UNIT_Y, - NULL); - UI_but_funcN_set( - but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_OPEN)); - } - else { - but = uiDefIconTextBut(block, - UI_BTYPE_BUT, - 0, - ICON_FILEBROWSER, - (id) ? "" : IFACE_("Open"), - 0, - 0, - w, - UI_UNIT_Y, - NULL, - 0, - 0, - 0, - 0, - NULL); - UI_but_funcN_set( - but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_OPEN)); - } - if ((idfrom && idfrom->lib) || !editable) { - UI_but_flag_enable(but, UI_BUT_DISABLED); - } + if (template_ui->idcode == ID_TE) { + uiTemplateTextureShow(layout, C, &template_ui->ptr, template_ui->prop); } - /* delete button */ - /* don't use RNA_property_is_unlink here */ - if (id && (flag & UI_ID_DELETE) && (hide_buttons == false)) { - /* allow unlink if 'unlinkop' is passed, even when 'PROP_NEVER_UNLINK' is set */ - but = NULL; - - if (unlinkop) { - but = uiDefIconButO(block, - UI_BTYPE_BUT, - unlinkop, - WM_OP_INVOKE_DEFAULT, - ICON_X, - 0, - 0, - UI_UNIT_X, - UI_UNIT_Y, - NULL); - /* so we can access the template from operators, font unlinking needs this */ - UI_but_funcN_set(but, NULL, MEM_dupallocN(template_ui), NULL); - } - else { - if ((RNA_property_flag(template_ui->prop) & PROP_NEVER_UNLINK) == 0) { - but = uiDefIconBut( - block, - UI_BTYPE_BUT, - 0, - ICON_X, - 0, - 0, - UI_UNIT_X, - UI_UNIT_Y, - NULL, - 0, - 0, - 0, - 0, - TIP_("Unlink data-block " - "(Shift + Click to set users to zero, data will then not be saved)")); - UI_but_funcN_set( - but, template_id_cb, MEM_dupallocN(template_ui), POINTER_FROM_INT(UI_ID_DELETE)); - - if (RNA_property_flag(template_ui->prop) & PROP_NEVER_NULL) { - UI_but_flag_enable(but, UI_BUT_DISABLED); - } - } - } - - if (but) { - if ((idfrom && idfrom->lib) || !editable) { - UI_but_flag_enable(but, UI_BUT_DISABLED); - } - } + if (id && !hide_buttons) { + /* Additional operations menu ("Make Local", overrides, etc). */ + but = uiDefIconMenuBut(block, + template_id_menu, + NULL, + ICON_DOWNARROW_HLT, + 0, + 0, + UI_UNIT_X, + UI_UNIT_Y, + TIP_("Show more operations for the selected data-block")); + UI_but_type_set_menu_from_pulldown(but); + /* Same hack as ui_item_menu() to allow allocated arg. */ + but->poin = (char *)but; + but->func_argN = MEM_dupallocN(template_ui); } - if (template_ui->idcode == ID_TE) { - uiTemplateTextureShow(layout, C, &template_ui->ptr, template_ui->prop); - } UI_block_align_end(block); } @@ -1212,7 +1503,6 @@ static void template_ID_tabs(const bContext *C, TemplateID *template, StructRNA *type, int flag, - const char *newop, const char *menu) { const ARegion *region = CTX_wm_region(C); @@ -1260,22 +1550,20 @@ static void template_ID_tabs(const bContext *C, BLI_freelistN(&ordered); if (flag & UI_ID_ADD_NEW) { - const bool editable = RNA_property_editable(&template->ptr, template->prop); uiBut *but; if (active_ptr.type) { type = active_ptr.type; } - but = template_id_def_new_but(block, - active_ptr.data, - template, - type, - newop, - editable, - flag & UI_ID_OPEN, - true, - but_height); + but = template_id_new_button(block, + active_ptr.data, + template, + TEMPLATE_ID_CREATE_NEW, + type, + flag & UI_ID_OPEN, + true, + but_height); UI_but_drawflag_enable(but, but_align); } } @@ -1285,6 +1573,7 @@ static void ui_template_id(uiLayout *layout, PointerRNA *ptr, const char *propname, const char *newop, + const char *duplicateop, const char *openop, const char *unlinkop, /* Only respected by tabs (use_tabs). */ @@ -1314,6 +1603,10 @@ static void ui_template_id(uiLayout *layout, template_ui = MEM_callocN(sizeof(TemplateID), "TemplateID"); template_ui->ptr = *ptr; template_ui->prop = prop; + template_ui->new_op = newop; + template_ui->duplicate_op = duplicateop; + template_ui->unlink_op = unlinkop; + template_ui->open_op = openop; template_ui->prv_rows = prv_rows; template_ui->prv_cols = prv_cols; template_ui->scale = scale; @@ -1325,7 +1618,7 @@ static void ui_template_id(uiLayout *layout, template_ui->filter = 0; } - if (newop) { + if (newop || duplicateop) { flag |= UI_ID_ADD_NEW; } if (openop) { @@ -1343,21 +1636,11 @@ static void ui_template_id(uiLayout *layout, if (template_ui->idlb) { if (use_tabs) { layout = uiLayoutRow(layout, true); - template_ID_tabs(C, layout, template_ui, type, flag, newop, menu); + template_ID_tabs(C, layout, template_ui, type, flag, menu); } else { layout = uiLayoutRow(layout, true); - template_ID(C, - layout, - template_ui, - type, - flag, - newop, - openop, - unlinkop, - text, - live_icon, - hide_buttons); + template_ID(C, layout, template_ui, type, flag, text, live_icon, hide_buttons); } } @@ -1369,6 +1652,7 @@ void uiTemplateID(uiLayout *layout, PointerRNA *ptr, const char *propname, const char *newop, + const char *duplicateop, const char *openop, const char *unlinkop, int filter, @@ -1380,6 +1664,7 @@ void uiTemplateID(uiLayout *layout, ptr, propname, newop, + duplicateop, openop, unlinkop, NULL, @@ -1409,6 +1694,7 @@ void uiTemplateIDBrowse(uiLayout *layout, ptr, propname, newop, + NULL, openop, unlinkop, NULL, @@ -1440,6 +1726,7 @@ void uiTemplateIDPreview(uiLayout *layout, ptr, propname, newop, + NULL, openop, unlinkop, NULL, @@ -1472,6 +1759,7 @@ void uiTemplateGpencilColorPreview(uiLayout *layout, NULL, NULL, NULL, + NULL, UI_ID_BROWSE | UI_ID_PREVIEWS | UI_ID_DELETE, rows, cols, @@ -1500,6 +1788,7 @@ void uiTemplateIDTabs(uiLayout *layout, newop, NULL, NULL, + NULL, menu, NULL, UI_ID_BROWSE | UI_ID_RENAME, @@ -1659,35 +1948,25 @@ static void template_search_add_button_searchmenu(const bContext *C, static void template_search_add_button_name(uiBlock *block, PointerRNA *active_ptr, - const StructRNA *type) + const StructRNA *type, + const char *newop, + const char *unlinkop) { - uiDefAutoButR(block, - active_ptr, - RNA_struct_name_property(type), - 0, - "", - ICON_NONE, - 0, - 0, - TEMPLATE_SEARCH_TEXTBUT_WIDTH, - TEMPLATE_SEARCH_TEXTBUT_HEIGHT); -} - -static void template_search_add_button_operator(uiBlock *block, - const char *const operator_name, - const int opcontext, - const int icon, - const bool editable) -{ - if (!operator_name) { - return; + uiBut *but = uiDefAutoButR(block, + active_ptr, + RNA_struct_name_property(type), + 0, + "", + ICON_NONE, + 0, + 0, + TEMPLATE_SEARCH_TEXTBUT_WIDTH, + TEMPLATE_SEARCH_TEXTBUT_HEIGHT); + if (newop) { + UI_but_extra_operator_icon_add(but, newop, WM_OP_INVOKE_DEFAULT, ICON_DUPLICATE); } - - uiBut *but = uiDefIconButO( - block, UI_BTYPE_BUT, operator_name, opcontext, icon, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL); - - if (!editable) { - UI_but_drawflag_enable(but, UI_BUT_DISABLED); + if (unlinkop) { + UI_but_extra_operator_icon_add(but, unlinkop, WM_OP_INVOKE_REGION_WIN, ICON_X); } } @@ -1713,10 +1992,7 @@ static void template_search_buttons(const bContext *C, UI_block_align_begin(block); template_search_add_button_searchmenu(C, layout, block, template_search, editable, false); - template_search_add_button_name(block, &active_ptr, type); - template_search_add_button_operator( - block, newop, WM_OP_INVOKE_DEFAULT, ICON_DUPLICATE, editable); - template_search_add_button_operator(block, unlinkop, WM_OP_INVOKE_REGION_WIN, ICON_X, editable); + template_search_add_button_name(block, &active_ptr, type, newop, unlinkop); UI_block_align_end(block); } @@ -2011,7 +2287,7 @@ static void set_constraint_expand_flag(const bContext *UNUSED(C), Panel *panel, /** * Function with void * argument for #uiListPanelIDFromDataFunc. * - * \note: Constraint panel types are assumed to be named with the struct name field + * \note Constraint panel types are assumed to be named with the struct name field * concatenated to the defined prefix. */ static void object_constraint_panel_id(void *md_link, char *r_name) @@ -2639,7 +2915,7 @@ static void draw_constraint_header(uiLayout *layout, Object *ob, bConstraint *co } else { /* enabled */ - UI_block_emboss_set(block, UI_EMBOSS_NONE); + UI_block_emboss_set(block, UI_EMBOSS_NONE_OR_STATUS); uiItemR(layout, &ptr, "mute", 0, "", 0); UI_block_emboss_set(block, UI_EMBOSS); @@ -6170,6 +6446,10 @@ void uiTemplateList(uiLayout *layout, org_i, flt_flag); + /* Items should be able to set context pointers for the layout. But the list-row button + * swallows events, so it needs the context storage too for handlers to see it. */ + but->context = uiLayoutGetContextStore(sub); + /* If we are "drawing" active item, set all labels as active. */ if (i == activei) { ui_layout_list_set_labels_active(sub); @@ -7184,6 +7464,7 @@ void uiTemplateCacheFile(uiLayout *layout, ptr, propname, NULL, + NULL, "CACHEFILE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 9c7b112855f..4d81b1edf0c 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -264,7 +264,7 @@ typedef struct uiWidgetType { /* converted colors for state */ uiWidgetColors wcol; - void (*state)(struct uiWidgetType *, int state, int drawflag, char emboss); + void (*state)(struct uiWidgetType *, int state, int drawflag, eUIEmbossType emboss); void (*draw)(uiWidgetColors *, rcti *, int state, int roundboxalign); void (*custom)(uiBut *, uiWidgetColors *, rcti *, int state, int roundboxalign); void (*text)(const uiFontStyle *, const uiWidgetColors *, uiBut *, rcti *); @@ -2520,8 +2520,14 @@ static void widget_active_color(uiWidgetColors *wcol) static const uchar *widget_color_blend_from_flags(const uiWidgetStateColors *wcol_state, int state, - int drawflag) + int drawflag, + const eUIEmbossType emboss) { + /* Explicitly require #UI_EMBOSS_NONE_OR_STATUS for color blending with no emboss. */ + if (emboss == UI_EMBOSS_NONE) { + return NULL; + } + if (drawflag & UI_BUT_ANIMATED_CHANGED) { return wcol_state->inner_changed_sel; } @@ -2541,7 +2547,7 @@ static const uchar *widget_color_blend_from_flags(const uiWidgetStateColors *wco } /* copy colors from theme, and set changes in it based on state */ -static void widget_state(uiWidgetType *wt, int state, int drawflag, char emboss) +static void widget_state(uiWidgetType *wt, int state, int drawflag, eUIEmbossType emboss) { uiWidgetStateColors *wcol_state = wt->wcol_state; @@ -2557,7 +2563,7 @@ static void widget_state(uiWidgetType *wt, int state, int drawflag, char emboss) wt->wcol = *(wt->wcol_theme); - const uchar *color_blend = widget_color_blend_from_flags(wcol_state, state, drawflag); + const uchar *color_blend = widget_color_blend_from_flags(wcol_state, state, drawflag, emboss); if (state & UI_SELECT) { copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.inner_sel); @@ -2619,14 +2625,14 @@ static void widget_state(uiWidgetType *wt, int state, int drawflag, char emboss) * \{ */ /* sliders use special hack which sets 'item' as inner when drawing filling */ -static void widget_state_numslider(uiWidgetType *wt, int state, int drawflag, char emboss) +static void widget_state_numslider(uiWidgetType *wt, int state, int drawflag, eUIEmbossType emboss) { uiWidgetStateColors *wcol_state = wt->wcol_state; /* call this for option button */ widget_state(wt, state, drawflag, emboss); - const uchar *color_blend = widget_color_blend_from_flags(wcol_state, state, drawflag); + const uchar *color_blend = widget_color_blend_from_flags(wcol_state, state, drawflag, emboss); if (color_blend != NULL) { /* Set the slider 'item' so that it reflects state settings too. * De-saturate so the color of the slider doesn't conflict with the blend color, @@ -2642,7 +2648,10 @@ static void widget_state_numslider(uiWidgetType *wt, int state, int drawflag, ch } /* labels use theme colors for text */ -static void widget_state_option_menu(uiWidgetType *wt, int state, int drawflag, char emboss) +static void widget_state_option_menu(uiWidgetType *wt, + int state, + int drawflag, + eUIEmbossType emboss) { const bTheme *btheme = UI_GetTheme(); @@ -2662,7 +2671,7 @@ static void widget_state_option_menu(uiWidgetType *wt, int state, int drawflag, static void widget_state_nothing(uiWidgetType *wt, int UNUSED(state), int UNUSED(drawflag), - char UNUSED(emboss)) + eUIEmbossType UNUSED(emboss)) { wt->wcol = *(wt->wcol_theme); } @@ -2671,7 +2680,7 @@ static void widget_state_nothing(uiWidgetType *wt, static void widget_state_pulldown(uiWidgetType *wt, int UNUSED(state), int UNUSED(drawflag), - char UNUSED(emboss)) + eUIEmbossType UNUSED(emboss)) { wt->wcol = *(wt->wcol_theme); } @@ -2680,7 +2689,7 @@ static void widget_state_pulldown(uiWidgetType *wt, static void widget_state_pie_menu_item(uiWidgetType *wt, int state, int UNUSED(drawflag), - char UNUSED(emboss)) + eUIEmbossType UNUSED(emboss)) { wt->wcol = *(wt->wcol_theme); @@ -2715,7 +2724,7 @@ static void widget_state_pie_menu_item(uiWidgetType *wt, static void widget_state_menu_item(uiWidgetType *wt, int state, int UNUSED(drawflag), - char UNUSED(emboss)) + eUIEmbossType UNUSED(emboss)) { wt->wcol = *(wt->wcol_theme); @@ -2906,12 +2915,12 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, const uiWidgetColors *wcol, const const bool is_color_gamma = ui_but_is_color_gamma(but); /* Initialize for compatibility. */ - copy_v3_v3(hsv, cpicker->color_data); + copy_v3_v3(hsv, cpicker->hsv_perceptual); /* Compute current hue. */ ui_but_v3_get(but, rgb); - ui_scene_linear_to_color_picker_space(but, rgb); - ui_rgb_to_color_picker_compat_v(rgb, hsv); + ui_scene_linear_to_perceptual_space(but, rgb); + ui_color_picker_rgb_to_hsv_compat(rgb, hsv); CLAMP(hsv[2], 0.0f, 1.0f); /* for display only */ @@ -2928,8 +2937,8 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, const uiWidgetColors *wcol, const } const float hsv_center[3] = {0.0f, 0.0f, hsv[2]}; - ui_color_picker_to_rgb_v(hsv_center, rgb_center); - ui_color_picker_to_scene_linear_space(but, rgb_center); + ui_color_picker_hsv_to_rgb(hsv_center, rgb_center); + ui_perceptual_to_scene_linear_space(but, rgb_center); if (!is_color_gamma) { ui_block_cm_to_display_space_v3(but->block, rgb_center); @@ -2956,8 +2965,8 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, const uiWidgetColors *wcol, const rect, centx + co * radius, centy + si * radius, hsv_ang, hsv_ang + 1); hsv_ang[2] = hsv[2]; - ui_color_picker_to_rgb_v(hsv_ang, rgb_ang); - ui_color_picker_to_scene_linear_space(but, rgb_ang); + ui_color_picker_hsv_to_rgb(hsv_ang, rgb_ang); + ui_perceptual_to_scene_linear_space(but, rgb_ang); if (!is_color_gamma) { ui_block_cm_to_display_space_v3(but->block, rgb_ang); @@ -2987,10 +2996,10 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, const uiWidgetColors *wcol, const GPU_line_smooth(false); /* cursor */ - copy_v3_v3(hsv, cpicker->color_data); + copy_v3_v3(hsv, cpicker->hsv_perceptual); ui_but_v3_get(but, rgb); - ui_scene_linear_to_color_picker_space(but, rgb); - ui_rgb_to_color_picker_compat_v(rgb, hsv); + ui_scene_linear_to_perceptual_space(but, rgb); + ui_color_picker_rgb_to_hsv_compat(rgb, hsv); float xpos, ypos; ui_hsvcircle_pos_from_vals(cpicker, rect, hsv, &xpos, &ypos); @@ -3212,14 +3221,14 @@ static void ui_draw_but_HSVCUBE(uiBut *but, const rcti *rect) float rgb[3]; float x = 0.0f, y = 0.0f; ColorPicker *cpicker = but->custom_data; - float *hsv = cpicker->color_data; + float *hsv = cpicker->hsv_perceptual; float hsv_n[3]; /* Initialize for compatibility. */ copy_v3_v3(hsv_n, hsv); ui_but_v3_get(but, rgb); - ui_scene_linear_to_color_picker_space(but, rgb); + ui_scene_linear_to_perceptual_space(but, rgb); rgb_to_hsv_compat_v(rgb, hsv_n); ui_draw_gradient(rect, hsv_n, hsv_but->gradient_type, 1.0f); @@ -3251,7 +3260,7 @@ static void ui_draw_but_HSV_v(uiBut *but, const rcti *rect) float rgb[3], hsv[3], v; ui_but_v3_get(but, rgb); - ui_scene_linear_to_color_picker_space(but, rgb); + ui_scene_linear_to_perceptual_space(but, rgb); if (hsv_but->gradient_type == UI_GRAD_L_ALT) { rgb_to_hsl_v(rgb, hsv); @@ -4064,7 +4073,7 @@ static void widget_optionbut(uiWidgetColors *wcol, } /* labels use Editor theme colors for text */ -static void widget_state_label(uiWidgetType *wt, int state, int drawflag, char emboss) +static void widget_state_label(uiWidgetType *wt, int state, int drawflag, eUIEmbossType emboss) { if (state & UI_BUT_LIST_ITEM) { /* Override default label theme's colors. */ @@ -4524,8 +4533,9 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu break; } } - else if (but->emboss == UI_EMBOSS_NONE) { - /* "nothing" */ + else if (ELEM(but->emboss, UI_EMBOSS_NONE, UI_EMBOSS_NONE_OR_STATUS)) { + /* Use the same widget types for both no emboss types. Later on, + * #UI_EMBOSS_NONE_OR_STATUS will blend state colors if they apply. */ switch (but->type) { case UI_BTYPE_LABEL: wt = widget_type(UI_WTYPE_ICON_LABEL); diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c index a5999962e09..7de0ec0255f 100644 --- a/source/blender/editors/interface/view2d_ops.c +++ b/source/blender/editors/interface/view2d_ops.c @@ -109,14 +109,13 @@ typedef struct v2dViewPanData { static bool view_pan_poll(bContext *C) { ARegion *region = CTX_wm_region(C); - View2D *v2d; /* check if there's a region in context to work with */ if (region == NULL) { return false; } - v2d = ®ion->v2d; + View2D *v2d = ®ion->v2d; /* check that 2d-view can pan */ if ((v2d->keepofs & V2D_LOCKOFS_X) && (v2d->keepofs & V2D_LOCKOFS_Y)) { @@ -191,10 +190,7 @@ static void view_pan_apply(bContext *C, wmOperator *op) /* cleanup temp customdata */ static void view_pan_exit(wmOperator *op) { - if (op->customdata) { - MEM_freeN(op->customdata); - op->customdata = NULL; - } + MEM_SAFE_FREE(op->customdata); } /** \} */ @@ -216,14 +212,12 @@ static int view_pan_exec(bContext *C, wmOperator *op) static int view_pan_invoke(bContext *C, wmOperator *op, const wmEvent *event) { wmWindow *window = CTX_wm_window(C); - v2dViewPanData *vpd; - View2D *v2d; /* set up customdata */ view_pan_init(C, op); - vpd = op->customdata; - v2d = vpd->v2d; + v2dViewPanData *vpd = op->customdata; + View2D *v2d = vpd->v2d; /* set initial settings */ vpd->startx = vpd->lastx = event->x; @@ -787,7 +781,6 @@ static void view_zoom_axis_lock_defaults(bContext *C, bool r_do_zoom_xy[2]) static bool view_zoom_poll(bContext *C) { ARegion *region = CTX_wm_region(C); - View2D *v2d; /* check if there's a region in context to work with */ if (region == NULL) { @@ -799,7 +792,7 @@ static bool view_zoom_poll(bContext *C) return false; } - v2d = ®ion->v2d; + View2D *v2d = ®ion->v2d; /* check that 2d-view is zoomable */ if ((v2d->keepzoom & V2D_LOCKZOOM_X) && (v2d->keepzoom & V2D_LOCKZOOM_Y)) { @@ -836,12 +829,12 @@ static void view_zoomstep_apply_ex(bContext *C, ARegion *region = CTX_wm_region(C); View2D *v2d = ®ion->v2d; const rctf cur_old = v2d->cur; - float dx, dy; const int snap_test = ED_region_snap_size_test(region); /* calculate amount to move view by, ensuring symmetry so the * old zoom level is restored after zooming back the same amount */ + float dx, dy; if (facx >= 0.0f) { dx = BLI_rctf_size_x(&v2d->cur) * facx; dy = BLI_rctf_size_y(&v2d->cur) * facy; @@ -955,10 +948,7 @@ static void view_zoomstep_exit(wmOperator *op) { UI_view2d_zoom_cache_reset(); - if (op->customdata) { - MEM_freeN(op->customdata); - op->customdata = NULL; - } + MEM_SAFE_FREE(op->customdata); } /* this operator only needs this single callback, where it calls the view_zoom_*() methods */ @@ -1107,15 +1097,14 @@ static void view_zoomdrag_apply(bContext *C, wmOperator *op) { v2dViewZoomData *vzd = op->customdata; View2D *v2d = vzd->v2d; - float dx, dy; const int snap_test = ED_region_snap_size_test(vzd->region); const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init"); const bool zoom_to_pos = use_cursor_init && vzd->zoom_to_mouse_pos; /* get amount to move view by */ - dx = RNA_float_get(op->ptr, "deltax") / U.dpi_fac; - dy = RNA_float_get(op->ptr, "deltay") / U.dpi_fac; + float dx = RNA_float_get(op->ptr, "deltax") / U.dpi_fac; + float dy = RNA_float_get(op->ptr, "deltay") / U.dpi_fac; if (U.uiflag & USER_ZOOM_INVERT) { dx *= -1; @@ -1223,14 +1212,12 @@ static int view_zoomdrag_exec(bContext *C, wmOperator *op) static int view_zoomdrag_invoke(bContext *C, wmOperator *op, const wmEvent *event) { wmWindow *window = CTX_wm_window(C); - v2dViewZoomData *vzd; - View2D *v2d; /* set up customdata */ view_zoomdrag_init(C, op); - vzd = op->customdata; - v2d = vzd->v2d; + v2dViewZoomData *vzd = op->customdata; + View2D *v2d = vzd->v2d; if (U.uiflag & USER_ZOOM_TO_MOUSEPOS) { ARegion *region = CTX_wm_region(C); @@ -1242,20 +1229,18 @@ static int view_zoomdrag_invoke(bContext *C, wmOperator *op, const wmEvent *even } if (ELEM(event->type, MOUSEZOOM, MOUSEPAN)) { - float dx, dy, fac; - vzd->lastx = event->prevx; vzd->lasty = event->prevy; /* As we have only 1D information (magnify value), feed both axes * with magnify information that is stored in x axis */ - fac = 0.01f * (event->prevx - event->x); - dx = fac * BLI_rctf_size_x(&v2d->cur) / 10.0f; + float fac = 0.01f * (event->prevx - event->x); + float dx = fac * BLI_rctf_size_x(&v2d->cur) / 10.0f; if (event->type == MOUSEPAN) { fac = 0.01f * (event->prevy - event->y); } - dy = fac * BLI_rctf_size_y(&v2d->cur) / 10.0f; + float dy = fac * BLI_rctf_size_y(&v2d->cur) / 10.0f; /* support trackpad zoom to always zoom entirely - the v2d code uses portrait or * landscape exceptions */ @@ -1491,11 +1476,11 @@ static int view_borderzoom_exec(bContext *C, wmOperator *op) { ARegion *region = CTX_wm_region(C); View2D *v2d = ®ion->v2d; - rctf rect; rctf cur_new = v2d->cur; const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); /* convert coordinates of rect to 'tot' rect coordinates */ + rctf rect; WM_operator_properties_border_to_rctf(op, &rect); UI_view2d_region_to_view_rctf(v2d, &rect, &rect); @@ -1766,13 +1751,13 @@ static int view2d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const w ARegion *region = CTX_wm_region(C); View2D *v2d = ®ion->v2d; struct SmoothView2DStore *sms = v2d->sms; - float step; /* escape if not our timer */ if (v2d->smooth_timer == NULL || v2d->smooth_timer != event->customdata) { return OPERATOR_PASS_THROUGH; } + float step; if (sms->time_allowed != 0.0) { step = (float)((v2d->smooth_timer->duration) / sms->time_allowed); } @@ -1978,15 +1963,11 @@ static void scroller_activate_init(bContext *C, const wmEvent *event, const char in_scroller) { - v2dScrollerMove *vsm; - View2DScrollers scrollers; ARegion *region = CTX_wm_region(C); View2D *v2d = ®ion->v2d; - rctf tot_cur_union; - float mask_size; /* set custom-data for operator */ - vsm = MEM_callocN(sizeof(v2dScrollerMove), "v2dScrollerMove"); + v2dScrollerMove *vsm = MEM_callocN(sizeof(v2dScrollerMove), "v2dScrollerMove"); op->customdata = vsm; /* set general data */ @@ -2000,16 +1981,17 @@ static void scroller_activate_init(bContext *C, /* 'zone' depends on where mouse is relative to bubble * - zooming must be allowed on this axis, otherwise, default to pan */ + View2DScrollers scrollers; UI_view2d_scrollers_calc(v2d, NULL, &scrollers); /* Use a union of 'cur' & 'tot' in case the current view is far outside 'tot'. In this cases * moving the scroll bars has far too little effect and the view can get stuck T31476. */ - tot_cur_union = v2d->tot; + rctf tot_cur_union = v2d->tot; BLI_rctf_union(&tot_cur_union, &v2d->cur); if (in_scroller == 'h') { /* horizontal scroller - calculate adjustment factor first */ - mask_size = (float)BLI_rcti_size_x(&v2d->hor); + float mask_size = (float)BLI_rcti_size_x(&v2d->hor); vsm->fac = BLI_rctf_size_x(&tot_cur_union) / mask_size; /* pixel rounding */ @@ -2029,7 +2011,7 @@ static void scroller_activate_init(bContext *C, } else { /* vertical scroller - calculate adjustment factor first */ - mask_size = (float)BLI_rcti_size_y(&v2d->vert); + float mask_size = (float)BLI_rcti_size_y(&v2d->vert); vsm->fac = BLI_rctf_size_y(&tot_cur_union) / mask_size; /* pixel rounding */ @@ -2076,10 +2058,9 @@ static void scroller_activate_apply(bContext *C, wmOperator *op) { v2dScrollerMove *vsm = op->customdata; View2D *v2d = vsm->v2d; - float temp; /* calculate amount to move view by */ - temp = vsm->fac * vsm->delta; + float temp = vsm->fac * vsm->delta; /* round to pixel */ temp = roundf(temp / vsm->fac_round) * vsm->fac_round; @@ -2219,11 +2200,9 @@ static int scroller_activate_invoke(bContext *C, wmOperator *op, const wmEvent * /* if in a scroller, init customdata then set modal handler which will * catch mouse-down to start doing useful stuff */ if (in_scroller) { - v2dScrollerMove *vsm; - /* initialize customdata */ scroller_activate_init(C, op, event, in_scroller); - vsm = (v2dScrollerMove *)op->customdata; + v2dScrollerMove *vsm = (v2dScrollerMove *)op->customdata; /* support for quick jump to location - gtk and qt do this on linux */ if (event->type == MIDDLEMOUSE) { @@ -2324,12 +2303,11 @@ static int reset_exec(bContext *C, wmOperator *UNUSED(op)) const uiStyle *style = UI_style_get(); ARegion *region = CTX_wm_region(C); View2D *v2d = ®ion->v2d; - int winx, winy; const int snap_test = ED_region_snap_size_test(region); /* zoom 1.0 */ - winx = (float)(BLI_rcti_size_x(&v2d->mask) + 1); - winy = (float)(BLI_rcti_size_y(&v2d->mask) + 1); + const int winx = (float)(BLI_rcti_size_x(&v2d->mask) + 1); + const int winy = (float)(BLI_rcti_size_y(&v2d->mask) + 1); v2d->cur.xmax = v2d->cur.xmin + winx; v2d->cur.ymax = v2d->cur.ymin + winy; diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index b8badd207fe..e788b28d3b4 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -1129,7 +1129,7 @@ void MESH_OT_bevel(wmOperatorType *ot) prop_affect_items, BEVEL_AFFECT_EDGES, "Affect", - "Affect Edges or Vertices"); + "Affect edges or vertices"); RNA_def_boolean(ot->srna, "clamp_overlap", diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c index ef78d31a6bb..aa144dd3f3c 100644 --- a/source/blender/editors/mesh/editmesh_knife_project.c +++ b/source/blender/editors/mesh/editmesh_knife_project.c @@ -177,6 +177,6 @@ void MESH_OT_knife_project(wmOperatorType *ot) RNA_def_boolean(ot->srna, "cut_through", false, - "Cut through", + "Cut Through", "Cut through all faces, not just visible ones"); } diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index a2fe949b6c5..d3eaa9048d3 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -4552,7 +4552,8 @@ void MESH_OT_select_non_manifold(wmOperatorType *ot) /* edges */ RNA_def_boolean(ot->srna, "use_wire", true, "Wire", "Wire edges"); RNA_def_boolean(ot->srna, "use_boundary", true, "Boundaries", "Boundary edges"); - RNA_def_boolean(ot->srna, "use_multi_face", true, "Multiple Faces", "Edges shared by 3+ faces"); + RNA_def_boolean( + ot->srna, "use_multi_face", true, "Multiple Faces", "Edges shared by more than two faces"); RNA_def_boolean(ot->srna, "use_non_contiguous", true, diff --git a/source/blender/editors/mesh/editmesh_select_similar.c b/source/blender/editors/mesh/editmesh_select_similar.c index 00349983c57..d762eede079 100644 --- a/source/blender/editors/mesh/editmesh_select_similar.c +++ b/source/blender/editors/mesh/editmesh_select_similar.c @@ -34,6 +34,7 @@ #include "BKE_material.h" #include "BKE_report.h" +#include "DNA_material_types.h" #include "DNA_meshdata_types.h" #include "WM_api.h" diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index aab17d6da61..59ce9140ab8 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -180,7 +180,7 @@ void MESH_OT_subdivide(wmOperatorType *ot) "ngon", true, "Create N-Gons", - "When disabled, newly created faces are limited to 3-4 sided faces"); + "When disabled, newly created faces are limited to 3 and 4 sided faces"); RNA_def_enum( ot->srna, "quadcorner", @@ -395,7 +395,7 @@ void MESH_OT_unsubdivide(wmOperatorType *ot) { /* identifiers */ ot->name = "Un-Subdivide"; - ot->description = "UnSubdivide selected edges & faces"; + ot->description = "Un-subdivide selected edges and faces"; ot->idname = "MESH_OT_unsubdivide"; /* api callbacks */ @@ -698,7 +698,7 @@ void MESH_OT_edge_collapse(wmOperatorType *ot) /* identifiers */ ot->name = "Collapse Edges & Faces"; ot->description = - "Collapse isolated edges & faces regions, merging data such as UV's and vertex colors. " + "Collapse isolated edge and face regions, merging data such as UV's and vertex colors. " "This can collapse edge-rings as well as regions of connected faces into vertices"; ot->idname = "MESH_OT_edge_collapse"; @@ -1904,7 +1904,7 @@ void MESH_OT_edge_split(wmOperatorType *ot) "VERT", 0, "Faces & Edges by Vertices", - "Split faces & edges connected to selected vertices"}, + "Split faces and edges connected to selected vertices"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c index 99f7992c2a9..b16b2809e51 100644 --- a/source/blender/editors/mesh/editmesh_undo.c +++ b/source/blender/editors/mesh/editmesh_undo.c @@ -27,6 +27,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" +#include "DNA_scene_types.h" #include "BLI_array_utils.h" #include "BLI_listbase.h" diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index 138e394a4d8..ce77f90c5fe 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -1140,8 +1140,10 @@ void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, if (use_topology) { v_mirr = cache_mirr_intptr_as_bmvert(mesh_topo_store.index_lookup, i); - if (respecthide && BM_elem_flag_test(v_mirr, BM_ELEM_HIDDEN)) { - v_mirr = NULL; + if (v_mirr != NULL) { + if (respecthide && BM_elem_flag_test(v_mirr, BM_ELEM_HIDDEN)) { + v_mirr = NULL; + } } } else { diff --git a/source/blender/editors/metaball/editmball_undo.c b/source/blender/editors/metaball/editmball_undo.c index 552e459acb1..b4030ad269b 100644 --- a/source/blender/editors/metaball/editmball_undo.c +++ b/source/blender/editors/metaball/editmball_undo.c @@ -30,8 +30,10 @@ #include "BLI_utildefines.h" #include "DNA_defs.h" +#include "DNA_layer_types.h" #include "DNA_meta_types.h" #include "DNA_object_types.h" +#include "DNA_scene_types.h" #include "BKE_context.h" #include "BKE_layer.h" diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt index a1be9b9df61..77b5379ddd4 100644 --- a/source/blender/editors/object/CMakeLists.txt +++ b/source/blender/editors/object/CMakeLists.txt @@ -31,8 +31,8 @@ set(INC ../../makesrna ../../modifiers ../../python - ../../shader_fx ../../render + ../../shader_fx ../../windowmanager ../../../../intern/clog ../../../../intern/glew-mx @@ -88,6 +88,7 @@ endif() if(WITH_EXPERIMENTAL_FEATURES) add_definitions(-DWITH_GEOMETRY_NODES) + add_definitions(-DWITH_POINT_CLOUD) add_definitions(-DWITH_HAIR_NODES) endif() diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 4e0f6211c18..a64033bc63a 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1618,6 +1618,7 @@ static int object_speaker_add_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } Object *ob = ED_object_add_type(C, OB_SPEAKER, NULL, loc, rot, false, local_view_bits); + const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ob); /* to make it easier to start using this immediately in NLA, a default sound clip is created * ready to be moved around to retime the sound and/or make new sound clips @@ -1625,13 +1626,13 @@ static int object_speaker_add_exec(bContext *C, wmOperator *op) { /* create new data for NLA hierarchy */ AnimData *adt = BKE_animdata_add_id(&ob->id); - NlaTrack *nlt = BKE_nlatrack_add(adt, NULL); + NlaTrack *nlt = BKE_nlatrack_add(adt, NULL, is_liboverride); NlaStrip *strip = BKE_nla_add_soundstrip(bmain, scene, ob->data); strip->start = CFRA; strip->end += strip->start; /* hook them up */ - BKE_nlatrack_add_strip(nlt, strip); + BKE_nlatrack_add_strip(nlt, strip, is_liboverride); /* auto-name the strip, and give the track an interesting name */ BLI_strncpy(nlt->name, DATA_("SoundTrack"), sizeof(nlt->name)); @@ -1713,6 +1714,9 @@ void OBJECT_OT_hair_add(wmOperatorType *ot) static bool object_pointcloud_add_poll(bContext *C) { + if (!U.experimental.use_new_point_cloud_type) { + return false; + } return ED_operator_objectmode(C); } @@ -2315,17 +2319,23 @@ static const EnumPropertyItem convert_target_items[] = { "MESH", ICON_OUTLINER_OB_MESH, "Mesh", +#ifdef WITH_POINT_CLOUD "Mesh from Curve, Surface, Metaball, Text, or Pointcloud objects"}, +#else + "Mesh from Curve, Surface, Metaball, or Text objects"}, +#endif {OB_GPENCIL, "GPENCIL", ICON_OUTLINER_OB_GREASEPENCIL, "Grease Pencil", "Grease Pencil from Curve or Mesh objects"}, +#ifdef WITH_POINT_CLOUD {OB_POINTCLOUD, "POINTCLOUD", ICON_OUTLINER_OB_POINTCLOUD, "Pointcloud", "Pointcloud from Mesh objects"}, +#endif {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c index 008498a1735..9618774eea8 100644 --- a/source/blender/editors/object/object_bake.c +++ b/source/blender/editors/object/object_bake.c @@ -25,6 +25,7 @@ #include "MEM_guardedalloc.h" +#include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index e684ad03f53..dd015f59e8d 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -706,8 +706,9 @@ static bool edit_constraint_poll_generic(bContext *C, return false; } - if (!is_liboverride_allowed && !BKE_constraint_is_local_in_liboverride(ob, con)) { - CTX_wm_operator_poll_msg_set(C, "Cannot edit constraints coming from library override"); + if (!is_liboverride_allowed && BKE_constraint_is_nonlocal_in_liboverride(ob, con)) { + CTX_wm_operator_poll_msg_set( + C, "Cannot edit constraints coming from linked data in a library override"); return false; } diff --git a/source/blender/editors/object/object_gpencil_modifier.c b/source/blender/editors/object/object_gpencil_modifier.c index d3f165678c3..e5feb74df26 100644 --- a/source/blender/editors/object/object_gpencil_modifier.c +++ b/source/blender/editors/object/object_gpencil_modifier.c @@ -443,9 +443,9 @@ static bool gpencil_edit_modifier_poll_generic(bContext *C, return false; } - if (!is_liboverride_allowed && - (mod == NULL || !BKE_gpencil_modifier_is_local_in_liboverride(ob, mod))) { - CTX_wm_operator_poll_msg_set(C, "Cannot edit modifiers coming from library override"); + if (!is_liboverride_allowed && BKE_gpencil_modifier_is_nonlocal_in_liboverride(ob, mod)) { + CTX_wm_operator_poll_msg_set( + C, "Cannot edit modifiers coming from linked data in a library override"); return false; } @@ -461,7 +461,7 @@ static bool gpencil_edit_modifier_poll(bContext *C) * (not only from added 'local' ones). */ static bool gpencil_edit_modifier_liboverride_allowed_poll(bContext *C) { - return gpencil_edit_modifier_poll_generic(C, &RNA_Modifier, 0, true); + return gpencil_edit_modifier_poll_generic(C, &RNA_GpencilModifier, 0, true); } static void gpencil_edit_modifier_properties(wmOperatorType *ot) @@ -789,7 +789,7 @@ void OBJECT_OT_gpencil_modifier_apply(wmOperatorType *ot) "apply_as", gpencil_modifier_apply_as_items, MODIFIER_APPLY_DATA, - "Apply as", + "Apply As", "How to apply the modifier to the geometry"); gpencil_edit_modifier_properties(ot); gpencil_edit_modifier_report_property(ot); diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index e6ef53a3d65..89ade5cc49d 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -206,6 +206,7 @@ void OBJECT_OT_gpencil_modifier_copy(struct wmOperatorType *ot); /* object_shader_fx.c */ void OBJECT_OT_shaderfx_add(struct wmOperatorType *ot); +void OBJECT_OT_shaderfx_copy(struct wmOperatorType *ot); void OBJECT_OT_shaderfx_remove(struct wmOperatorType *ot); void OBJECT_OT_shaderfx_move_up(struct wmOperatorType *ot); void OBJECT_OT_shaderfx_move_down(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index bb4581b0ee8..3111003703f 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -1052,8 +1052,9 @@ bool edit_modifier_poll_generic(bContext *C, return false; } - if (!is_liboverride_allowed && !BKE_modifier_is_local_in_liboverride(ob, mod)) { - CTX_wm_operator_poll_msg_set(C, "Cannot edit modifiers coming from library override"); + if (!is_liboverride_allowed && BKE_modifier_is_nonlocal_in_liboverride(ob, mod)) { + CTX_wm_operator_poll_msg_set( + C, "Cannot edit modifiers coming from linked data in a library override"); return false; } diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index 8ba0ce5fd08..2e5a75ffa7d 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -166,6 +166,7 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_shaderfx_move_up); WM_operatortype_append(OBJECT_OT_shaderfx_move_down); WM_operatortype_append(OBJECT_OT_shaderfx_move_to_index); + WM_operatortype_append(OBJECT_OT_shaderfx_copy); WM_operatortype_append(OBJECT_OT_correctivesmooth_bind); WM_operatortype_append(OBJECT_OT_meshdeform_bind); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 8841b1955bf..ee9ef192d18 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -484,7 +484,7 @@ void OBJECT_OT_proxy_make(wmOperatorType *ot) DummyRNA_DEFAULT_items, 0, "Proxy Object", - "Name of lib-linked/collection object to make a proxy for"); + "Name of library-linked/collection object to make a proxy for"); RNA_def_enum_funcs(prop, proxy_collection_object_itemf); RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); ot->prop = prop; @@ -1554,6 +1554,7 @@ enum { MAKE_LINKS_DUPLICOLLECTION = 5, MAKE_LINKS_MODIFIERS = 6, MAKE_LINKS_FONTS = 7, + MAKE_LINKS_SHADERFX = 8, }; /* Return true if make link data is allowed, false otherwise */ @@ -1589,6 +1590,11 @@ static bool allow_make_links_data(const int type, Object *ob_src, Object *ob_dst return true; } break; + case MAKE_LINKS_SHADERFX: + if ((ob_src->type == OB_GPENCIL) && (ob_dst->type == OB_GPENCIL)) { + return true; + } + break; } return false; } @@ -1720,6 +1726,11 @@ static int make_links_data_exec(bContext *C, wmOperator *op) ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); break; } + case MAKE_LINKS_SHADERFX: + ED_object_shaderfx_link(ob_dst, ob_src); + DEG_id_tag_update(&ob_dst->id, + ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); + break; } } } @@ -1782,6 +1793,7 @@ void OBJECT_OT_make_links_data(wmOperatorType *ot) {MAKE_LINKS_DUPLICOLLECTION, "DUPLICOLLECTION", 0, "Instance Collection", ""}, {MAKE_LINKS_MODIFIERS, "MODIFIERS", 0, "Modifiers", ""}, {MAKE_LINKS_FONTS, "FONTS", 0, "Fonts", ""}, + {MAKE_LINKS_SHADERFX, "EFFECTS", 0, "Effects", ""}, {0, NULL, 0, NULL, NULL}, }; @@ -2515,7 +2527,7 @@ static bool convert_proxy_to_override_poll(bContext *C) return obact != NULL && obact->proxy != NULL; } -static int convert_proxy_to_override_exec(bContext *C, wmOperator *UNUSED(op)) +static int convert_proxy_to_override_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); @@ -2529,6 +2541,15 @@ static int convert_proxy_to_override_exec(bContext *C, wmOperator *UNUSED(op)) const bool success = BKE_lib_override_library_proxy_convert(bmain, scene, view_layer, ob_proxy); + if (!success) { + BKE_reportf( + op->reports, + RPT_ERROR_INVALID_INPUT, + "Could not create a library override from proxy '%s' (might use already local data?)", + ob_proxy->id.name + 2); + return OPERATOR_CANCELLED; + } + /* Remove the instance empty from this scene, the items now have an overridden collection * instead. */ if (success && is_override_instancing_object) { @@ -2544,7 +2565,7 @@ static int convert_proxy_to_override_exec(bContext *C, wmOperator *UNUSED(op)) void OBJECT_OT_convert_proxy_to_override(wmOperatorType *ot) { /* identifiers */ - ot->name = "Convert Proxy To Override"; + ot->name = "Convert Proxy to Override"; ot->description = "Convert a proxy to a local library override"; ot->idname = "OBJECT_OT_convert_proxy_to_override"; diff --git a/source/blender/editors/object/object_shader_fx.c b/source/blender/editors/object/object_shader_fx.c index c5caee5ba08..2b1ac08ec2e 100644 --- a/source/blender/editors/object/object_shader_fx.c +++ b/source/blender/editors/object/object_shader_fx.c @@ -640,3 +640,57 @@ void OBJECT_OT_shaderfx_move_to_index(wmOperatorType *ot) RNA_def_int( ot->srna, "index", 0, 0, INT_MAX, "Index", "The index to move the effect to", 0, INT_MAX); } + +/************************ copy shader operator *********************/ + +static int shaderfx_copy_exec(bContext *C, wmOperator *op) +{ + Object *ob = ED_object_active_context(C); + ShaderFxData *fx = edit_shaderfx_property_get(op, ob, 0); + + ShaderFxData *nfx = BKE_shaderfx_new(fx->type); + if (!nfx) { + return OPERATOR_CANCELLED; + } + + BLI_strncpy(nfx->name, fx->name, sizeof(nfx->name)); + /* Make sure effect data has unique name. */ + BKE_shaderfx_unique_name(&ob->shader_fx, nfx); + + BKE_shaderfx_copydata(fx, nfx); + BLI_insertlinkafter(&ob->shader_fx, fx, nfx); + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_main_add_notifier(NC_OBJECT | ND_SHADERFX, ob); + + return OPERATOR_FINISHED; +} + +static int shaderfx_copy_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + int retval; + if (edit_shaderfx_invoke_properties(C, op, event, &retval)) { + return shaderfx_copy_exec(C, op); + } + return retval; +} + +static bool shaderfx_copy_poll(bContext *C) +{ + return edit_shaderfx_poll_generic(C, &RNA_ShaderFx, 0); +} + +void OBJECT_OT_shaderfx_copy(wmOperatorType *ot) +{ + ot->name = "Copy Effect"; + ot->description = "Duplicate effect at the same position in the stack"; + ot->idname = "OBJECT_OT_shaderfx_copy"; + + ot->invoke = shaderfx_copy_invoke; + ot->exec = shaderfx_copy_exec; + ot->poll = shaderfx_copy_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + edit_shaderfx_properties(ot); +} diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index 3d6a6abfe0d..fc4969019b5 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -736,14 +736,19 @@ const EnumPropertyItem *ED_object_vgroup_selection_itemf_helper(const bContext * RNA_enum_items_add_value(&item, &totitem, WT_vertex_group_select_item, WT_VGROUP_ACTIVE); } - if (BKE_object_pose_armature_get(ob)) { - if (selection_mask & (1 << WT_VGROUP_BONE_SELECT)) { - RNA_enum_items_add_value( - &item, &totitem, WT_vertex_group_select_item, WT_VGROUP_BONE_SELECT); + if (ob) { + if (BKE_object_pose_armature_get(ob)) { + if (selection_mask & (1 << WT_VGROUP_BONE_SELECT)) { + RNA_enum_items_add_value( + &item, &totitem, WT_vertex_group_select_item, WT_VGROUP_BONE_SELECT); + } } - if (selection_mask & (1 << WT_VGROUP_BONE_DEFORM)) { - RNA_enum_items_add_value( - &item, &totitem, WT_vertex_group_select_item, WT_VGROUP_BONE_DEFORM); + + if (BKE_modifiers_is_deformed_by_armature(ob)) { + if (selection_mask & (1 << WT_VGROUP_BONE_DEFORM)) { + RNA_enum_items_add_value( + &item, &totitem, WT_vertex_group_select_item, WT_VGROUP_BONE_DEFORM); + } } } diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c index 017cd63d9d5..f5c3fc17552 100644 --- a/source/blender/editors/physics/particle_object.c +++ b/source/blender/editors/physics/particle_object.c @@ -1203,6 +1203,9 @@ static bool copy_particle_systems_to_object(const bContext *C, #undef PSYS_FROM_FIRST #undef PSYS_FROM_NEXT + if (duplicate_settings) { + DEG_relations_tag_update(bmain); + } DEG_id_tag_update(&ob_to->id, ID_RECALC_GEOMETRY); WM_main_add_notifier(NC_OBJECT | ND_PARTICLE | NA_EDITED, ob_to); return true; diff --git a/source/blender/editors/physics/rigidbody_constraint.c b/source/blender/editors/physics/rigidbody_constraint.c index 4939bf0086b..cb7ca5bd5d1 100644 --- a/source/blender/editors/physics/rigidbody_constraint.c +++ b/source/blender/editors/physics/rigidbody_constraint.c @@ -25,6 +25,7 @@ #include <stdlib.h> #include <string.h> +#include "DNA_collection_types.h" #include "DNA_object_types.h" #include "DNA_rigidbody_types.h" #include "DNA_scene_types.h" diff --git a/source/blender/editors/physics/rigidbody_object.c b/source/blender/editors/physics/rigidbody_object.c index cb25363d2b2..4fd304ea71d 100644 --- a/source/blender/editors/physics/rigidbody_object.c +++ b/source/blender/editors/physics/rigidbody_object.c @@ -25,6 +25,7 @@ #include <stdlib.h> #include <string.h> +#include "DNA_collection_types.h" #include "DNA_object_types.h" #include "DNA_rigidbody_types.h" #include "DNA_scene_types.h" diff --git a/source/blender/editors/render/render_intern.h b/source/blender/editors/render/render_intern.h index e1d03e6f3be..e60455667e9 100644 --- a/source/blender/editors/render/render_intern.h +++ b/source/blender/editors/render/render_intern.h @@ -38,8 +38,11 @@ void OBJECT_OT_material_slot_move(struct wmOperatorType *ot); void OBJECT_OT_material_slot_remove_unused(struct wmOperatorType *ot); void MATERIAL_OT_new(struct wmOperatorType *ot); +void MATERIAL_OT_duplicate(struct wmOperatorType *ot); void TEXTURE_OT_new(struct wmOperatorType *ot); +void TEXTURE_OT_duplicate(struct wmOperatorType *ot); void WORLD_OT_new(struct wmOperatorType *ot); +void WORLD_OT_duplicate(struct wmOperatorType *ot); void MATERIAL_OT_copy(struct wmOperatorType *ot); void MATERIAL_OT_paste(struct wmOperatorType *ot); diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index 3dbf70aa4bc..10cf4131584 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -29,6 +29,7 @@ #include "BLI_listbase.h" #include "BLI_math.h" +#include "BLI_rect.h" #include "BLI_threads.h" #include "BLI_timecode.h" #include "BLI_utildefines.h" @@ -82,7 +83,7 @@ #include "RNA_access.h" #include "RNA_define.h" -#include "SEQ_sequencer.h" +#include "SEQ_relations.h" #include "BLO_undofile.h" @@ -121,72 +122,90 @@ typedef struct RenderJob { } RenderJob; /* called inside thread! */ -static void image_buffer_rect_update(RenderJob *rj, - RenderResult *rr, - ImBuf *ibuf, - ImageUser *iuser, - volatile rcti *renrect, - const char *viewname) +static bool image_buffer_calc_tile_rect(const RenderResult *rr, + const ImBuf *ibuf, + volatile rcti *renrect, + rcti *r_ibuf_rect, + int *r_offset_x, + int *r_offset_y) { - Scene *scene = rj->scene; - const float *rectf = NULL; - int ymin, ymax, xmin, xmax; - int rymin, rxmin; - int linear_stride, linear_offset_x, linear_offset_y; - ColorManagedViewSettings *view_settings; - ColorManagedDisplaySettings *display_settings; - - if (ibuf->userflags & IB_DISPLAY_BUFFER_INVALID) { - /* The whole image buffer it so be color managed again anyway. */ - return; - } + int tile_y, tile_height, tile_x, tile_width; /* if renrect argument, we only refresh scanlines */ if (renrect) { - /* if (ymax == recty), rendering of layer is ready, + /* if (tile_height == recty), rendering of layer is ready, * we should not draw, other things happen... */ if (rr->renlay == NULL || renrect->ymax >= rr->recty) { - return; + return false; } - /* xmin here is first subrect x coord, xmax defines subrect width */ - xmin = renrect->xmin + rr->crop; - xmax = renrect->xmax - xmin + rr->crop; - if (xmax < 2) { - return; + /* tile_x here is first subrect x coord, tile_width defines subrect width */ + tile_x = renrect->xmin; + tile_width = renrect->xmax - tile_x; + if (tile_width < 2) { + return false; } - ymin = renrect->ymin + rr->crop; - ymax = renrect->ymax - ymin + rr->crop; - if (ymax < 2) { - return; + tile_y = renrect->ymin; + tile_height = renrect->ymax - tile_y; + if (tile_height < 2) { + return false; } renrect->ymin = renrect->ymax; } else { - xmin = ymin = rr->crop; - xmax = rr->rectx - 2 * rr->crop; - ymax = rr->recty - 2 * rr->crop; + tile_x = tile_y = 0; + tile_width = rr->rectx; + tile_height = rr->recty; } - /* xmin ymin is in tile coords. transform to ibuf */ - rxmin = rr->tilerect.xmin + xmin; - if (rxmin >= ibuf->x) { - return; + /* tile_x tile_y is in tile coords. transform to ibuf */ + int offset_x = rr->tilerect.xmin; + if (offset_x >= ibuf->x) { + return false; } - rymin = rr->tilerect.ymin + ymin; - if (rymin >= ibuf->y) { - return; + int offset_y = rr->tilerect.ymin; + if (offset_y >= ibuf->y) { + return false; } - if (rxmin + xmax > ibuf->x) { - xmax = ibuf->x - rxmin; + if (offset_x + tile_width > ibuf->x) { + tile_width = ibuf->x - offset_x; } - if (rymin + ymax > ibuf->y) { - ymax = ibuf->y - rymin; + if (offset_y + tile_height > ibuf->y) { + tile_height = ibuf->y - offset_y; } - if (xmax < 1 || ymax < 1) { + if (tile_width < 1 || tile_height < 1) { + return false; + } + + r_ibuf_rect->xmax = tile_x + tile_width; + r_ibuf_rect->ymax = tile_y + tile_height; + r_ibuf_rect->xmin = tile_x; + r_ibuf_rect->ymin = tile_y; + *r_offset_x = offset_x; + *r_offset_y = offset_y; + return true; +} + +static void image_buffer_rect_update(RenderJob *rj, + RenderResult *rr, + ImBuf *ibuf, + ImageUser *iuser, + const rcti *tile_rect, + int offset_x, + int offset_y, + const char *viewname) +{ + Scene *scene = rj->scene; + const float *rectf = NULL; + int linear_stride, linear_offset_x, linear_offset_y; + ColorManagedViewSettings *view_settings; + ColorManagedDisplaySettings *display_settings; + + if (ibuf->userflags & IB_DISPLAY_BUFFER_INVALID) { + /* The whole image buffer is to be color managed again anyway. */ return; } @@ -230,10 +249,10 @@ static void image_buffer_rect_update(RenderJob *rj, return; } - rectf += 4 * (rr->rectx * ymin + xmin); + rectf += 4 * (rr->rectx * tile_rect->ymin + tile_rect->xmin); linear_stride = rr->rectx; - linear_offset_x = rxmin; - linear_offset_y = rymin; + linear_offset_x = offset_x; + linear_offset_y = offset_y; } else { rectf = ibuf->rect_float; @@ -253,10 +272,10 @@ static void image_buffer_rect_update(RenderJob *rj, linear_offset_y, view_settings, display_settings, - rxmin, - rymin, - rxmin + xmax, - rymin + ymax); + offset_x, + offset_y, + offset_x + BLI_rcti_size_x(tile_rect), + offset_y + BLI_rcti_size_y(tile_rect)); } /* ****************************** render invoking ***************** */ @@ -344,7 +363,7 @@ static int screen_render_exec(bContext *C, wmOperator *op) * otherwise, invalidated cache entries can make their way into * the output rendering. We can't put that into RE_RenderFrame, * since sequence rendering can call that recursively... (peter) */ - BKE_sequencer_cache_cleanup(scene); + SEQ_cache_cleanup(scene); RE_SetReports(re, op->reports); @@ -578,8 +597,16 @@ static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrec /* update part of render */ render_image_update_pass_and_layer(rj, rr, &rj->iuser); + rcti tile_rect; + int offset_x; + int offset_y; ibuf = BKE_image_acquire_ibuf(ima, &rj->iuser, &lock); if (ibuf) { + if (!image_buffer_calc_tile_rect(rr, ibuf, renrect, &tile_rect, &offset_x, &offset_y)) { + BKE_image_release_ibuf(ima, ibuf, lock); + return; + } + /* Don't waste time on CPU side color management if * image will be displayed using GLSL. * @@ -589,9 +616,10 @@ static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrec */ if (!rj->supports_glsl_draw || ibuf->channels == 1 || ED_draw_imbuf_method(ibuf) != IMAGE_DRAW_METHOD_GLSL) { - image_buffer_rect_update(rj, rr, ibuf, &rj->iuser, renrect, viewname); + image_buffer_rect_update(rj, rr, ibuf, &rj->iuser, &tile_rect, offset_x, offset_y, viewname); } - ima->gpuflag |= IMA_GPU_REFRESH; + BKE_image_update_gputexture_delayed( + ima, ibuf, offset_x, offset_y, BLI_rcti_size_x(&tile_rect), BLI_rcti_size_y(&tile_rect)); /* make jobs timer to send notifier */ *(rj->do_update) = true; @@ -907,7 +935,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even /* Reports are done inside check function, and it will return false if there are other strips to * render. */ - if ((scene->r.scemode & R_DOSEQ) && BKE_sequencer_check_scene_recursion(scene, op->reports)) { + if ((scene->r.scemode & R_DOSEQ) && SEQ_relations_check_scene_recursion(scene, op->reports)) { return OPERATOR_CANCELLED; } @@ -929,7 +957,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even * otherwise, invalidated cache entries can make their way into * the output rendering. We can't put that into RE_RenderFrame, * since sequence rendering can call that recursively... (peter) */ - BKE_sequencer_cache_cleanup(scene); + SEQ_cache_cleanup(scene); /* store spare * get view3d layer, local layer, make this nice api call to render diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index f7275b06804..1069f942a7a 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -77,7 +77,7 @@ #include "RNA_access.h" #include "RNA_define.h" -#include "SEQ_sequencer.h" +#include "SEQ_render.h" #include "GPU_framebuffer.h" #include "GPU_matrix.h" diff --git a/source/blender/editors/render/render_ops.c b/source/blender/editors/render/render_ops.c index e0aa02b354d..48e894036d9 100644 --- a/source/blender/editors/render/render_ops.c +++ b/source/blender/editors/render/render_ops.c @@ -45,8 +45,11 @@ void ED_operatortypes_render(void) WM_operatortype_append(OBJECT_OT_material_slot_remove_unused); WM_operatortype_append(MATERIAL_OT_new); + WM_operatortype_append(MATERIAL_OT_duplicate); WM_operatortype_append(TEXTURE_OT_new); + WM_operatortype_append(TEXTURE_OT_duplicate); WM_operatortype_append(WORLD_OT_new); + WM_operatortype_append(WORLD_OT_duplicate); WM_operatortype_append(MATERIAL_OT_copy); WM_operatortype_append(MATERIAL_OT_paste); diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index 095deccada0..579fd86077e 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -68,6 +68,7 @@ #include "BKE_main.h" #include "BKE_material.h" #include "BKE_node.h" +#include "BKE_object.h" #include "BKE_scene.h" #include "BKE_texture.h" #include "BKE_world.h" @@ -94,12 +95,16 @@ #include "ED_datafiles.h" #include "ED_render.h" #include "ED_screen.h" +#include "ED_view3d.h" +#include "ED_view3d_offscreen.h" #ifndef NDEBUG /* Used for database init assert(). */ # include "BLI_threads.h" #endif +static void icon_copy_rect(ImBuf *ibuf, uint w, uint h, uint *rect); + ImBuf *get_brush_icon(Brush *brush) { static const int flags = IB_rect | IB_multilayer | IB_metadata; @@ -184,7 +189,7 @@ typedef struct IconPreview { Main *bmain; Scene *scene; void *owner; - ID *id, *id_copy; + ID *id, *id_copy; /* May be NULL! (see ICON_TYPE_PREVIEW case in #ui_icon_ensure_deferred()) */ ListBase sizes; } IconPreview; @@ -336,7 +341,7 @@ static World *preview_get_localized_world(ShaderPreview *sp, World *world) return sp->worldcopy; } -static ID *duplicate_ids(ID *id) +static ID *duplicate_ids(ID *id, const bool allow_failure) { if (id == NULL) { /* Non-ID preview render. */ @@ -344,20 +349,25 @@ static ID *duplicate_ids(ID *id) } switch (GS(id->name)) { + case ID_OB: case ID_MA: case ID_TE: case ID_LA: case ID_WO: { + BLI_assert(BKE_previewimg_id_supports_jobs(id)); ID *id_copy = BKE_id_copy_ex( NULL, id, NULL, LIB_ID_CREATE_LOCAL | LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_NO_ANIMDATA); return id_copy; } + /* These support threading, but don't need duplicating. */ case ID_IM: case ID_BR: - case ID_SCR: + BLI_assert(BKE_previewimg_id_supports_jobs(id)); return NULL; default: - BLI_assert(!"ID type preview not supported."); + if (!allow_failure) { + BLI_assert(!"ID type preview not supported."); + } return NULL; } } @@ -698,6 +708,132 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r } } +/* **************************** Object preview ****************** */ + +struct ObjectPreviewData { + /* The main for the preview, not of the current file. */ + Main *pr_main; + /* Copy of the object to create the preview for. The copy is for thread safety (and to insert it + * into an own main). */ + Object *object; + int sizex; + int sizey; +}; + +static Object *object_preview_camera_create( + Main *preview_main, ViewLayer *view_layer, Object *preview_object, int sizex, int sizey) +{ + Object *camera = BKE_object_add(preview_main, view_layer, OB_CAMERA, "Preview Camera"); + + float rotmat[3][3]; + float dummyscale[3]; + mat4_to_loc_rot_size(camera->loc, rotmat, dummyscale, preview_object->obmat); + + /* Camera is Y up, so needs additional 90deg rotation around X to match object's Z up. */ + float drotmat[3][3]; + axis_angle_to_mat3_single(drotmat, 'X', M_PI_2); + mul_m3_m3_post(rotmat, drotmat); + + camera->rotmode = ROT_MODE_QUAT; + mat3_to_quat(camera->quat, rotmat); + + /* shader_preview_render() does this too. */ + if (sizex > sizey) { + ((Camera *)camera->data)->lens *= (float)sizey / (float)sizex; + } + + return camera; +} + +static Scene *object_preview_scene_create(const struct ObjectPreviewData *preview_data, + Depsgraph **r_depsgraph) +{ + Scene *scene = BKE_scene_add(preview_data->pr_main, "Object preview scene"); + ViewLayer *view_layer = scene->view_layers.first; + Depsgraph *depsgraph = DEG_graph_new( + preview_data->pr_main, scene, view_layer, DAG_EVAL_VIEWPORT); + + BLI_assert(preview_data->object != NULL); + BLI_addtail(&preview_data->pr_main->objects, preview_data->object); + + BKE_collection_object_add(preview_data->pr_main, scene->master_collection, preview_data->object); + + Object *camera_object = object_preview_camera_create(preview_data->pr_main, + view_layer, + preview_data->object, + preview_data->sizex, + preview_data->sizey); + + scene->camera = camera_object; + scene->r.xsch = preview_data->sizex; + scene->r.ysch = preview_data->sizey; + scene->r.size = 100; + + Base *preview_base = BKE_view_layer_base_find(view_layer, preview_data->object); + /* For 'view selected' below. */ + preview_base->flag |= BASE_SELECTED; + + DEG_graph_build_from_view_layer(depsgraph); + DEG_evaluate_on_refresh(depsgraph); + + ED_view3d_camera_to_view_selected(preview_data->pr_main, depsgraph, scene, camera_object); + + BKE_scene_graph_update_tagged(depsgraph, preview_data->pr_main); + + *r_depsgraph = depsgraph; + return scene; +} + +static void object_preview_render(IconPreview *preview, IconPreviewSize *preview_sized) +{ + Main *preview_main = BKE_main_new(); + const float pixelsize_old = U.pixelsize; + char err_out[256] = "unknown"; + + BLI_assert(preview->id_copy && (preview->id_copy != preview->id)); + + struct ObjectPreviewData preview_data = { + .pr_main = preview_main, + /* Act on a copy. */ + .object = (Object *)preview->id_copy, + .sizex = preview_sized->sizex, + .sizey = preview_sized->sizey, + }; + Depsgraph *depsgraph; + Scene *scene = object_preview_scene_create(&preview_data, &depsgraph); + + /* Ownership is now ours. */ + preview->id_copy = NULL; + + U.pixelsize = 2.0f; + + ImBuf *ibuf = ED_view3d_draw_offscreen_imbuf_simple( + depsgraph, + DEG_get_evaluated_scene(depsgraph), + NULL, + OB_SOLID, + DEG_get_evaluated_object(depsgraph, scene->camera), + preview_sized->sizex, + preview_sized->sizey, + IB_rect, + V3D_OFSDRAW_NONE, + R_ALPHAPREMUL, + NULL, + NULL, + err_out); + /* TODO color-management? */ + + U.pixelsize = pixelsize_old; + + if (ibuf) { + icon_copy_rect(ibuf, preview_sized->sizex, preview_sized->sizey, preview_sized->rect); + IMB_freeImBuf(ibuf); + } + + DEG_graph_free(depsgraph); + BKE_main_free(preview_main); +} + /* **************************** new shader preview system ****************** */ /* inside thread, called by renderer, sets job update value */ @@ -1101,6 +1237,8 @@ static void icon_preview_startjob(void *customdata, short *stop, short *do_updat ID *id = sp->id; short idtype = GS(id->name); + BLI_assert(id != NULL); + if (idtype == ID_IM) { Image *ima = (Image *)id; ImBuf *ibuf = NULL; @@ -1188,27 +1326,72 @@ static void common_preview_startjob(void *customdata, } } -/* exported functions */ - -static void icon_preview_add_size(IconPreview *ip, uint *rect, int sizex, int sizey) +/** + * Some ID types already have their own, more focused rendering (only objects right now). This is + * for the other ones, which all share #ShaderPreview and some functions. + */ +static void other_id_types_preview_render(IconPreview *ip, + IconPreviewSize *cur_size, + const bool is_deferred, + short *stop, + short *do_update, + float *progress) { - IconPreviewSize *cur_size = ip->sizes.first, *new_size; + ShaderPreview *sp = MEM_callocN(sizeof(ShaderPreview), "Icon ShaderPreview"); + const bool is_render = !is_deferred; + + /* These types don't use the ShaderPreview mess, they have their own types and functions. */ + BLI_assert(!ip->id || !ELEM(GS(ip->id->name), ID_OB)); + + /* construct shader preview from image size and previewcustomdata */ + sp->scene = ip->scene; + sp->owner = ip->owner; + sp->sizex = cur_size->sizex; + sp->sizey = cur_size->sizey; + sp->pr_method = is_render ? PR_ICON_RENDER : PR_ICON_DEFERRED; + sp->pr_rect = cur_size->rect; + sp->id = ip->id; + sp->id_copy = ip->id_copy; + sp->bmain = ip->bmain; + sp->own_id_copy = false; + Material *ma = NULL; - while (cur_size) { - if (cur_size->sizex == sizex && cur_size->sizey == sizey) { - /* requested size is already in list, no need to add it again */ - return; + if (is_render) { + BLI_assert(ip->id); + + /* grease pencil use its own preview file */ + if (GS(ip->id->name) == ID_MA) { + ma = (Material *)ip->id; } - cur_size = cur_size->next; + if ((ma == NULL) || (ma->gp_style == NULL)) { + sp->pr_main = G_pr_main; + } + else { + sp->pr_main = G_pr_main_grease_pencil; + } } - new_size = MEM_callocN(sizeof(IconPreviewSize), "IconPreviewSize"); - new_size->sizex = sizex; - new_size->sizey = sizey; - new_size->rect = rect; + common_preview_startjob(sp, stop, do_update, progress); + shader_preview_free(sp); +} - BLI_addtail(&ip->sizes, new_size); +/* exported functions */ + +/** + * Find the index to map \a icon_size to data in \a preview_image. + */ +static int icon_previewimg_size_index_get(const IconPreviewSize *icon_size, + const PreviewImage *preview_image) +{ + for (int i = 0; i < NUM_ICON_SIZES; i++) { + if ((preview_image->w[i] == icon_size->sizex) && (preview_image->h[i] == icon_size->sizey)) { + return i; + } + } + + BLI_assert(!"The searched icon size does not match any in the preview image"); + return -1; } static void icon_preview_startjob_all_sizes(void *customdata, @@ -1235,41 +1418,43 @@ static void icon_preview_startjob_all_sizes(void *customdata, continue; } - ShaderPreview *sp = MEM_callocN(sizeof(ShaderPreview), "Icon ShaderPreview"); - const bool is_render = !(prv->tag & PRV_TAG_DEFFERED); - - /* construct shader preview from image size and previewcustomdata */ - sp->scene = ip->scene; - sp->owner = ip->owner; - sp->sizex = cur_size->sizex; - sp->sizey = cur_size->sizey; - sp->pr_method = is_render ? PR_ICON_RENDER : PR_ICON_DEFERRED; - sp->pr_rect = cur_size->rect; - sp->id = ip->id; - sp->id_copy = ip->id_copy; - sp->bmain = ip->bmain; - sp->own_id_copy = false; - Material *ma = NULL; - - if (is_render) { - BLI_assert(ip->id); - - /* grease pencil use its own preview file */ - if (GS(ip->id->name) == ID_MA) { - ma = (Material *)ip->id; - } +#ifndef NDEBUG + { + int size_index = icon_previewimg_size_index_get(cur_size, prv); + BLI_assert(!BKE_previewimg_is_finished(prv, size_index)); + } +#endif - if ((ma == NULL) || (ma->gp_style == NULL)) { - sp->pr_main = G_pr_main; - } - else { - sp->pr_main = G_pr_main_grease_pencil; - } + if (ip->id && ELEM(GS(ip->id->name), ID_OB)) { + /* Much simpler than the ShaderPreview mess used for other ID types. */ + object_preview_render(ip, cur_size); + } + else { + other_id_types_preview_render( + ip, cur_size, (prv->tag & PRV_TAG_DEFFERED), stop, do_update, progress); + } + } +} + +static void icon_preview_add_size(IconPreview *ip, uint *rect, int sizex, int sizey) +{ + IconPreviewSize *cur_size = ip->sizes.first, *new_size; + + while (cur_size) { + if (cur_size->sizex == sizex && cur_size->sizey == sizey) { + /* requested size is already in list, no need to add it again */ + return; } - common_preview_startjob(sp, stop, do_update, progress); - shader_preview_free(sp); + cur_size = cur_size->next; } + + new_size = MEM_callocN(sizeof(IconPreviewSize), "IconPreviewSize"); + new_size->sizex = sizex; + new_size->sizey = sizey; + new_size->rect = rect; + + BLI_addtail(&ip->sizes, new_size); } static void icon_preview_endjob(void *customdata) @@ -1302,9 +1487,15 @@ static void icon_preview_endjob(void *customdata) if (ip->owner) { PreviewImage *prv_img = ip->owner; prv_img->tag &= ~PRV_TAG_DEFFERED_RENDERING; + + LISTBASE_FOREACH (IconPreviewSize *, icon_size, &ip->sizes) { + int size_index = icon_previewimg_size_index_get(icon_size, prv_img); + BKE_previewimg_finish(prv_img, size_index); + } + if (prv_img->tag & PRV_TAG_DEFFERED_DELETE) { BLI_assert(prv_img->tag & PRV_TAG_DEFFERED); - BKE_previewimg_cached_release_pointer(prv_img); + BKE_previewimg_deferred_release(prv_img); } } } @@ -1333,7 +1524,9 @@ void ED_preview_icon_render(Main *bmain, Scene *scene, ID *id, uint *rect, int s ip.scene = scene; ip.owner = BKE_previewimg_id_ensure(id); ip.id = id; - ip.id_copy = duplicate_ids(id); + /* Control isn't given back to the caller until the preview is done. So we don't need to copy + * the ID to avoid thread races. */ + ip.id_copy = duplicate_ids(id, true); icon_preview_add_size(&ip, rect, sizex, sizey); @@ -1376,7 +1569,7 @@ void ED_preview_icon_job( ip->scene = CTX_data_scene(C); ip->owner = owner; ip->id = id; - ip->id_copy = duplicate_ids(id); + ip->id_copy = duplicate_ids(id, false); icon_preview_add_size(ip, rect, sizex, sizey); @@ -1416,6 +1609,8 @@ void ED_preview_shader_job(const bContext *C, Scene *scene = CTX_data_scene(C); short id_type = GS(id->name); + BLI_assert(BKE_previewimg_id_supports_jobs(id)); + /* Use workspace render only for buttons Window, * since the other previews are related to the datablock. */ @@ -1445,7 +1640,7 @@ void ED_preview_shader_job(const bContext *C, sp->sizey = sizey; sp->pr_method = method; sp->id = id; - sp->id_copy = duplicate_ids(id); + sp->id_copy = duplicate_ids(id, false); sp->own_id_copy = true; sp->parent = parent; sp->slot = slot; diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index b69337b1621..cac01bdc048 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -735,45 +735,40 @@ void OBJECT_OT_material_slot_remove_unused(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \name New Material Operator +/** \name Create Material Operators * \{ */ -static int new_material_exec(bContext *C, wmOperator *UNUSED(op)) +struct MaterialCreationData { + Object *ob; + PropertyPointerRNA pprop; +}; + +static void material_creation_data_init_from_UI_context(bContext *C, + struct MaterialCreationData *r_create_data) { - Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data; - Main *bmain = CTX_data_main(C); - PointerRNA ptr, idptr; + PointerRNA ptr; PropertyRNA *prop; /* hook into UI */ UI_context_active_but_prop_get_templateID(C, &ptr, &prop); - Object *ob = (prop && RNA_struct_is_a(ptr.type, &RNA_Object)) ? ptr.data : NULL; + r_create_data->ob = (prop && RNA_struct_is_a(ptr.type, &RNA_Object)) ? ptr.data : NULL; + r_create_data->pprop.ptr = ptr; + r_create_data->pprop.prop = prop; +} - /* add or copy material */ - if (ma) { - Material *new_ma = (Material *)BKE_id_copy_ex( - bmain, &ma->id, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS); - ma = new_ma; - } - else { - const char *name = DATA_("Material"); - if (!(ob != NULL && ob->type == OB_GPENCIL)) { - ma = BKE_material_add(bmain, name); - } - else { - ma = BKE_gpencil_material_add(bmain, name); - } - ED_node_shader_default(C, &ma->id); - ma->use_nodes = true; - } +static void material_creation_assign(bContext *C, + Material *ma, + struct MaterialCreationData *create_data) +{ + Main *bmain = CTX_data_main(C); - if (prop) { - if (ob != NULL) { + if (create_data->pprop.prop) { + if (create_data->ob != NULL) { /* Add slot follows user-preferences for creating new slots, * RNA pointer assignment doesn't, see: T60014. */ - if (BKE_object_material_get_p(ob, ob->actcol) == NULL) { - BKE_object_material_slot_add(bmain, ob); + if (BKE_object_material_get_p(create_data->ob, create_data->ob->actcol) == NULL) { + BKE_object_material_slot_add(bmain, create_data->ob); } } @@ -781,10 +776,32 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op)) * pointer use also increases user, so this compensates it */ id_us_min(&ma->id); + PointerRNA idptr; RNA_id_pointer_create(&ma->id, &idptr); - RNA_property_pointer_set(&ptr, prop, idptr, NULL); - RNA_property_update(C, &ptr, prop); + RNA_property_pointer_set(&create_data->pprop.ptr, create_data->pprop.prop, idptr, NULL); + RNA_property_update(C, &create_data->pprop.ptr, create_data->pprop.prop); + } +} + +static int new_material_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Main *bmain = CTX_data_main(C); + struct MaterialCreationData create_data; + + material_creation_data_init_from_UI_context(C, &create_data); + + const char *name = DATA_("Material"); + Material *ma; + if ((create_data.ob == NULL) || (create_data.ob->type != OB_GPENCIL)) { + ma = BKE_material_add(bmain, name); + } + else { + ma = BKE_gpencil_material_add(bmain, name); } + ED_node_shader_default(C, &ma->id); + ma->use_nodes = true; + + material_creation_assign(C, ma, &create_data); WM_event_add_notifier(C, NC_MATERIAL | NA_ADDED, ma); @@ -806,27 +823,57 @@ void MATERIAL_OT_new(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; } -/** \} */ +static int duplicate_material_exec(bContext *C, wmOperator *op) +{ + Material *old_ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data; + + if (!old_ma) { + BKE_report( + op->reports, + RPT_ERROR, + "Incorrect context for duplicating a material (did not find material to duplicate)"); + return OPERATOR_CANCELLED; + } + + Main *bmain = CTX_data_main(C); + struct MaterialCreationData create_data; + + material_creation_data_init_from_UI_context(C, &create_data); + + Material *new_ma = (Material *)BKE_id_copy_ex( + bmain, &old_ma->id, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS); + + material_creation_assign(C, new_ma, &create_data); + + WM_event_add_notifier(C, NC_MATERIAL | NA_ADDED, new_ma); + + return OPERATOR_FINISHED; +} + +void MATERIAL_OT_duplicate(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Duplicate Material"; + ot->idname = "MATERIAL_OT_duplicate"; + ot->description = "Duplicate an existing material"; + + /* api callbacks */ + ot->exec = duplicate_material_exec; + ot->poll = object_materials_supported_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; +} /* -------------------------------------------------------------------- */ -/** \name New Texture Operator +/** \name Create Texture Operators * \{ */ -static int new_texture_exec(bContext *C, wmOperator *UNUSED(op)) +static void texture_creation_assign(bContext *C, Tex *tex) { - Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data; - Main *bmain = CTX_data_main(C); PointerRNA ptr, idptr; PropertyRNA *prop; - /* add or copy texture */ - if (tex) { - tex = (Tex *)BKE_id_copy(bmain, &tex->id); - } - else { - tex = BKE_texture_add(bmain, DATA_("Texture")); - } - /* hook into UI */ UI_context_active_but_prop_get_templateID(C, &ptr, &prop); @@ -839,6 +886,14 @@ static int new_texture_exec(bContext *C, wmOperator *UNUSED(op)) RNA_property_pointer_set(&ptr, prop, idptr, NULL); RNA_property_update(C, &ptr, prop); } +} + +static int new_texture_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Main *bmain = CTX_data_main(C); + Tex *tex = BKE_texture_add(bmain, DATA_("Texture")); + + texture_creation_assign(C, tex); WM_event_add_notifier(C, NC_TEXTURE | NA_ADDED, tex); @@ -859,31 +914,53 @@ void TEXTURE_OT_new(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; } +static int duplicate_texture_exec(bContext *C, wmOperator *op) +{ + Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data; + + if (!tex) { + BKE_report(op->reports, + RPT_ERROR, + "Incorrect context for duplicating a texture (did not find texture to duplicate)"); + return OPERATOR_CANCELLED; + } + + /* add or copy texture */ + Main *bmain = CTX_data_main(C); + tex = (Tex *)BKE_id_copy(bmain, &tex->id); + + texture_creation_assign(C, tex); + + WM_event_add_notifier(C, NC_TEXTURE | NA_ADDED, tex); + + return OPERATOR_FINISHED; +} + +void TEXTURE_OT_duplicate(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Duplicate Texture"; + ot->idname = "TEXTURE_OT_duplicate"; + ot->description = "Duplicate an existing texture"; + + /* api callbacks */ + ot->exec = duplicate_texture_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; +} + /** \} */ /* -------------------------------------------------------------------- */ -/** \name new world operator +/** \name Create world operators * \{ */ -static int new_world_exec(bContext *C, wmOperator *UNUSED(op)) +static void world_creation_assign(bContext *C, World *wo) { - World *wo = CTX_data_pointer_get_type(C, "world", &RNA_World).data; - Main *bmain = CTX_data_main(C); PointerRNA ptr, idptr; PropertyRNA *prop; - /* add or copy world */ - if (wo) { - World *new_wo = (World *)BKE_id_copy_ex( - bmain, &wo->id, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS); - wo = new_wo; - } - else { - wo = BKE_world_add(bmain, DATA_("World")); - ED_node_shader_default(C, &wo->id); - wo->use_nodes = true; - } - /* hook into UI */ UI_context_active_but_prop_get_templateID(C, &ptr, &prop); @@ -896,6 +973,17 @@ static int new_world_exec(bContext *C, wmOperator *UNUSED(op)) RNA_property_pointer_set(&ptr, prop, idptr, NULL); RNA_property_update(C, &ptr, prop); } +} + +static int new_world_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Main *bmain = CTX_data_main(C); + + World *wo = BKE_world_add(bmain, DATA_("World")); + ED_node_shader_default(C, &wo->id); + wo->use_nodes = true; + + world_creation_assign(C, wo); WM_event_add_notifier(C, NC_WORLD | NA_ADDED, wo); @@ -907,7 +995,7 @@ void WORLD_OT_new(wmOperatorType *ot) /* identifiers */ ot->name = "New World"; ot->idname = "WORLD_OT_new"; - ot->description = "Create a new world Data-Block"; + ot->description = "Create a new world data-block"; /* api callbacks */ ot->exec = new_world_exec; @@ -916,6 +1004,36 @@ void WORLD_OT_new(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; } +static int duplicate_world_exec(bContext *C, wmOperator *UNUSED(op)) +{ + World *wo = CTX_data_pointer_get_type(C, "world", &RNA_World).data; + + if (wo) { + Main *bmain = CTX_data_main(C); + wo = (World *)BKE_id_copy(bmain, &wo->id); + } + + world_creation_assign(C, wo); + + WM_event_add_notifier(C, NC_WORLD | NA_ADDED, wo); + + return OPERATOR_FINISHED; +} + +void WORLD_OT_duplicate(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Duplicate World"; + ot->idname = "WORLD_OT_duplicate"; + ot->description = "Duplicate an existing world data-block"; + + /* api callbacks */ + ot->exec = duplicate_world_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c index 244ebea5bbe..1dfe606be78 100644 --- a/source/blender/editors/screen/screen_context.c +++ b/source/blender/editors/screen/screen_context.c @@ -604,7 +604,7 @@ static eContextResult screen_ctx_sequences(const bContext *C, bContextDataResult { wmWindow *win = CTX_wm_window(C); Scene *scene = WM_window_get_active_scene(win); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (ed) { LISTBASE_FOREACH (Sequence *, seq, ed->seqbasep) { CTX_data_list_add(result, &scene->id, &RNA_Sequence, seq); @@ -618,7 +618,7 @@ static eContextResult screen_ctx_selected_sequences(const bContext *C, bContextD { wmWindow *win = CTX_wm_window(C); Scene *scene = WM_window_get_active_scene(win); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (ed) { LISTBASE_FOREACH (Sequence *, seq, ed->seqbasep) { if (seq->flag & SELECT) { @@ -635,7 +635,7 @@ static eContextResult screen_ctx_selected_editable_sequences(const bContext *C, { wmWindow *win = CTX_wm_window(C); Scene *scene = WM_window_get_active_scene(win); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (ed) { LISTBASE_FOREACH (Sequence *, seq, ed->seqbasep) { if (seq->flag & SELECT && !(seq->flag & SEQ_LOCK)) { @@ -649,8 +649,6 @@ static eContextResult screen_ctx_selected_editable_sequences(const bContext *C, } static eContextResult screen_ctx_selected_nla_strips(const bContext *C, bContextDataResult *result) { - wmWindow *win = CTX_wm_window(C); - Scene *scene = WM_window_get_active_scene(win); bAnimContext ac; if (ANIM_animdata_get_context(C, &ac) != 0) { ListBase anim_data = {NULL, NULL}; @@ -663,7 +661,7 @@ static eContextResult screen_ctx_selected_nla_strips(const bContext *C, bContext NlaTrack *nlt = (NlaTrack *)ale->data; LISTBASE_FOREACH (NlaStrip *, strip, &nlt->strips) { if (strip->flag & NLASTRIP_FLAG_SELECT) { - CTX_data_list_add(result, &scene->id, &RNA_NlaStrip, strip); + CTX_data_list_add(result, ale->id, &RNA_NlaStrip, strip); } } } diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index 6be2fb8004b..be52874ed0b 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -1133,12 +1133,11 @@ void ED_screen_scene_change(bContext *C, wmWindow *win, Scene *scene) ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *area, int type) { - wmWindow *win = CTX_wm_window(C); ScrArea *newsa = NULL; SpaceLink *newsl; if (!area || area->full == NULL) { - newsa = ED_screen_state_toggle(C, win, area, SCREENMAXIMIZED); + newsa = ED_screen_state_maximized_create(C); } if (!newsa) { @@ -1149,11 +1148,11 @@ ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *area, int type) newsl = newsa->spacedata.first; /* Tag the active space before changing, so we can identify it when user wants to go back. */ - if ((newsl->link_flag & SPACE_FLAG_TYPE_TEMPORARY) == 0) { + if (newsl && (newsl->link_flag & SPACE_FLAG_TYPE_TEMPORARY) == 0) { newsl->link_flag |= SPACE_FLAG_TYPE_WAS_ACTIVE; } - ED_area_newspace(C, newsa, type, newsl->link_flag & SPACE_FLAG_TYPE_TEMPORARY); + ED_area_newspace(C, newsa, type, (newsl && newsl->link_flag & SPACE_FLAG_TYPE_TEMPORARY)); return newsa; } @@ -1217,13 +1216,108 @@ void ED_screen_full_restore(bContext *C, ScrArea *area) } /** - * this function toggles: if area is maximized/full then the parent will be restored + * \param toggle_area: If this is set, its space data will be swapped with the one of the new emtpy + * area, when toggling back it can be swapped back again. + * \return The newly created screen with the non-normal area. + */ +static bScreen *screen_state_to_nonnormal(bContext *C, + wmWindow *win, + ScrArea *toggle_area, + int state) +{ + Main *bmain = CTX_data_main(C); + WorkSpace *workspace = WM_window_get_active_workspace(win); + + /* change from SCREENNORMAL to new state */ + WorkSpaceLayout *layout_new; + ScrArea *newa; + char newname[MAX_ID_NAME - 2]; + + BLI_assert(ELEM(state, SCREENMAXIMIZED, SCREENFULL)); + + bScreen *oldscreen = WM_window_get_active_screen(win); + + oldscreen->state = state; + BLI_snprintf(newname, sizeof(newname), "%s-%s", oldscreen->id.name + 2, "nonnormal"); + + layout_new = ED_workspace_layout_add(bmain, workspace, win, newname); + + bScreen *screen = BKE_workspace_layout_screen_get(layout_new); + screen->state = state; + screen->redraws_flag = oldscreen->redraws_flag; + screen->temp = oldscreen->temp; + screen->flag = oldscreen->flag; + + /* timer */ + screen->animtimer = oldscreen->animtimer; + oldscreen->animtimer = NULL; + + newa = (ScrArea *)screen->areabase.first; + + /* swap area */ + if (toggle_area) { + ED_area_data_swap(newa, toggle_area); + newa->flag = toggle_area->flag; /* mostly for AREA_FLAG_WASFULLSCREEN */ + } + + if (state == SCREENFULL) { + /* temporarily hide global areas */ + LISTBASE_FOREACH (ScrArea *, glob_area, &win->global_areas.areabase) { + glob_area->global->flag |= GLOBAL_AREA_IS_HIDDEN; + } + /* temporarily hide the side panels/header */ + LISTBASE_FOREACH (ARegion *, region, &newa->regionbase) { + region->flagfullscreen = region->flag; + + if (ELEM(region->regiontype, + RGN_TYPE_UI, + RGN_TYPE_HEADER, + RGN_TYPE_TOOL_HEADER, + RGN_TYPE_FOOTER, + RGN_TYPE_TOOLS, + RGN_TYPE_NAV_BAR, + RGN_TYPE_EXECUTE)) { + region->flag |= RGN_FLAG_HIDDEN; + } + } + } + + if (toggle_area) { + toggle_area->full = oldscreen; + } + newa->full = oldscreen; + + ED_screen_change(C, screen); + ED_area_tag_refresh(newa); + + return screen; +} + +/** + * Create a new temporary screen with a maximized, empty area. + * This can be closed with #ED_screen_state_toggle(). + * + * Use this to just create a new maximized screen/area, rather than maximizing an existing one. + * Otherwise, maximize with #ED_screen_state_toggle(). + */ +ScrArea *ED_screen_state_maximized_create(bContext *C) +{ + bScreen *screen = screen_state_to_nonnormal(C, CTX_wm_window(C), NULL, SCREENMAXIMIZED); + return screen->areabase.first; +} + +/** + * This function toggles: if area is maximized/full then the parent will be restored. + * + * Use #ED_screen_state_maximized_create() if you do not want the toggle behavior when changing to + * a maximized area. I.e. if you just want to open a new maximized screen/area, not maximize a + * specific area. In the former case, space data of the maximized and non-maximized area should be + * independent, in the latter it should be the same. * * \warning \a area may be freed. */ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const short state) { - Main *bmain = CTX_data_main(C); wmWindowManager *wm = CTX_wm_manager(C); WorkSpace *workspace = WM_window_get_active_workspace(win); @@ -1257,7 +1351,7 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const screen->state = SCREENNORMAL; screen->flag = oldscreen->flag; - /* find old area to restore from */ + /* Find old area we may have swapped dummy space data to. It's swapped back here. */ ScrArea *fullsa = NULL; LISTBASE_FOREACH (ScrArea *, old, &screen->areabase) { /* area to restore from is always first */ @@ -1271,13 +1365,6 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const area->full = NULL; - if (fullsa == NULL) { - if (G.debug & G_DEBUG) { - printf("%s: something wrong in areafullscreen\n", __func__); - } - return NULL; - } - if (state == SCREENFULL) { /* unhide global areas */ LISTBASE_FOREACH (ScrArea *, glob_area, &win->global_areas.areabase) { @@ -1289,14 +1376,16 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const } } - ED_area_data_swap(fullsa, area); + if (fullsa) { + ED_area_data_swap(fullsa, area); + ED_area_tag_refresh(fullsa); + } /* animtimer back */ screen->animtimer = oldscreen->animtimer; oldscreen->animtimer = NULL; ED_screen_change(C, screen); - ED_area_tag_refresh(fullsa); BKE_workspace_layout_remove(CTX_data_main(C), workspace, layout_old); @@ -1307,68 +1396,16 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const screen->skip_handling = true; } else { - /* change from SCREENNORMAL to new state */ - WorkSpaceLayout *layout_new; - ScrArea *newa; - char newname[MAX_ID_NAME - 2]; - - BLI_assert(ELEM(state, SCREENMAXIMIZED, SCREENFULL)); - - bScreen *oldscreen = WM_window_get_active_screen(win); - - oldscreen->state = state; - BLI_snprintf(newname, sizeof(newname), "%s-%s", oldscreen->id.name + 2, "nonnormal"); - - layout_new = ED_workspace_layout_add(bmain, workspace, win, newname); - - screen = BKE_workspace_layout_screen_get(layout_new); - screen->state = state; - screen->redraws_flag = oldscreen->redraws_flag; - screen->temp = oldscreen->temp; - screen->flag = oldscreen->flag; - - /* timer */ - screen->animtimer = oldscreen->animtimer; - oldscreen->animtimer = NULL; + ScrArea *toggle_area = area; /* use random area when we have no active one, e.g. when the * mouse is outside of the window and we open a file browser */ - if (!area || area->global) { - area = oldscreen->areabase.first; + if (!toggle_area || toggle_area->global) { + bScreen *oldscreen = WM_window_get_active_screen(win); + toggle_area = oldscreen->areabase.first; } - newa = (ScrArea *)screen->areabase.first; - - /* copy area */ - ED_area_data_swap(newa, area); - newa->flag = area->flag; /* mostly for AREA_FLAG_WASFULLSCREEN */ - - if (state == SCREENFULL) { - /* temporarily hide global areas */ - LISTBASE_FOREACH (ScrArea *, glob_area, &win->global_areas.areabase) { - glob_area->global->flag |= GLOBAL_AREA_IS_HIDDEN; - } - /* temporarily hide the side panels/header */ - LISTBASE_FOREACH (ARegion *, region, &newa->regionbase) { - region->flagfullscreen = region->flag; - - if (ELEM(region->regiontype, - RGN_TYPE_UI, - RGN_TYPE_HEADER, - RGN_TYPE_TOOL_HEADER, - RGN_TYPE_FOOTER, - RGN_TYPE_TOOLS, - RGN_TYPE_NAV_BAR, - RGN_TYPE_EXECUTE)) { - region->flag |= RGN_FLAG_HIDDEN; - } - } - } - - area->full = oldscreen; - newa->full = oldscreen; - - ED_screen_change(C, screen); + screen = screen_state_to_nonnormal(C, win, toggle_area, state); } /* XXX bad code: setscreen() ends with first area active. fullscreen render assumes this too */ @@ -1412,9 +1449,6 @@ ScrArea *ED_screen_temp_space_open(bContext *C, area->flag |= AREA_FLAG_STACKED_FULLSCREEN; ((SpaceLink *)area->spacedata.first)->link_flag |= SPACE_FLAG_TYPE_TEMPORARY; } - else if (ctx_area != NULL && ctx_area->spacetype == space_type) { - area = ED_screen_state_toggle(C, CTX_wm_window(C), ctx_area, SCREENMAXIMIZED); - } else { area = ED_screen_full_newspace(C, ctx_area, (int)space_type); ((SpaceLink *)area->spacedata.first)->link_flag |= SPACE_FLAG_TYPE_TEMPORARY; diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 72b3b344813..8768404d74f 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -3918,7 +3918,7 @@ static void SCREEN_OT_region_quadview(wmOperatorType *ot) { /* identifiers */ ot->name = "Toggle Quad View"; - ot->description = "Split selected area into camera, front, right & top views"; + ot->description = "Split selected area into camera, front, right, and top views"; ot->idname = "SCREEN_OT_region_quadview"; /* api callbacks */ @@ -5509,7 +5509,8 @@ void ED_operatortypes_screen(void) WM_operatortype_append(ED_OT_undo_redo); WM_operatortype_append(ED_OT_undo_history); - WM_operatortype_append(ED_OT_flush_edits); + WM_operatortype_append(ED_OT_lib_id_load_custom_preview); + WM_operatortype_append(ED_OT_lib_id_generate_preview); } /** \} */ diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index 9bf3d2610d8..fff8d27ef5b 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -32,6 +32,7 @@ set(INC ../../windowmanager ../../../../intern/atomic ../../../../intern/clog + ../../../../intern/eigen ../../../../intern/glew-mx ../../../../intern/guardedalloc ) diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index 3a6b91443a0..324fd5d3075 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -40,6 +40,7 @@ #include "IMB_imbuf_types.h" #include "DNA_brush_types.h" +#include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_node_types.h" #include "DNA_object_types.h" @@ -934,7 +935,7 @@ void PAINT_OT_grab_clone(wmOperatorType *ot) -FLT_MAX, FLT_MAX, "Delta", - "Delta offset of clone image in 0.0..1.0 coordinates", + "Delta offset of clone image in 0.0 to 1.0 coordinates", -1.0f, 1.0f); } diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 8c16300a047..cca4ffd4d78 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -6748,7 +6748,7 @@ void PAINT_OT_add_texture_paint_slot(wmOperatorType *ot) "Generated Type", "Fill the image with a grid for UV map testing"); RNA_def_boolean( - ot->srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth"); + ot->srna, "float", 0, "32-bit Float", "Create image with 32-bit floating-point bit depth"); } static int add_simple_uvs_exec(bContext *C, wmOperator *UNUSED(op)) @@ -6781,7 +6781,7 @@ static bool add_simple_uvs_poll(bContext *C) void PAINT_OT_add_simple_uvs(wmOperatorType *ot) { /* identifiers */ - ot->name = "Add simple UVs"; + ot->name = "Add Simple UVs"; ot->description = "Add cube map uvs on mesh"; ot->idname = "PAINT_OT_add_simple_uvs"; diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h index 175d98ba9aa..3ca0d853d6a 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.h +++ b/source/blender/editors/sculpt_paint/paint_intern.h @@ -43,7 +43,6 @@ struct wmEvent; struct wmKeyConfig; struct wmOperator; struct wmOperatorType; -struct wmWindowManager; enum ePaintMode; enum ePaintSymmetryFlags; diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index 4bfb4f140bc..713049137ce 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -1554,6 +1554,11 @@ static int sculpt_trim_gesture_box_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } + if (ss->totvert == 0) { + /* No geometry to trim or to detect a valid position for the trimming shape. */ + return OPERATOR_CANCELLED; + } + SculptGestureContext *sgcontext = sculpt_gesture_init_from_box(C, op); if (!sgcontext) { return OPERATOR_CANCELLED; @@ -1591,6 +1596,11 @@ static int sculpt_trim_gesture_lasso_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } + if (ss->totvert == 0) { + /* No geometry to trim or to detect a valid position for the trimming shape. */ + return OPERATOR_CANCELLED; + } + SculptGestureContext *sgcontext = sculpt_gesture_init_from_lasso(C, op); if (!sgcontext) { return OPERATOR_CANCELLED; diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c index b831687ca67..96d22fe4a21 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c +++ b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c @@ -401,7 +401,7 @@ void PAINT_OT_vertex_color_brightness_contrast(wmOperatorType *ot) PropertyRNA *prop; /* identifiers */ - ot->name = "Vertex Paint Bright/Contrast"; + ot->name = "Vertex Paint Brightness/Contrast"; ot->idname = "PAINT_OT_vertex_color_brightness_contrast"; ot->description = "Adjust vertex color brightness/contrast"; diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index dd654b41ffa..bf55d6a323e 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -1539,6 +1539,7 @@ static bool sculpt_tool_is_proxy_used(const char sculpt_tool) SCULPT_TOOL_SMOOTH, SCULPT_TOOL_LAYER, SCULPT_TOOL_POSE, + SCULPT_TOOL_DISPLACEMENT_SMEAR, SCULPT_TOOL_BOUNDARY, SCULPT_TOOL_CLOTH, SCULPT_TOOL_PAINT, @@ -2703,6 +2704,7 @@ static float brush_strength(const Sculpt *sd, final_pressure = pressure * pressure; return final_pressure * overlap * feather; case SCULPT_TOOL_SMEAR: + case SCULPT_TOOL_DISPLACEMENT_SMEAR: return alpha * pressure * overlap * feather; case SCULPT_TOOL_CLAY_STRIPS: /* Clay Strips needs less strength to compensate the curve. */ @@ -3446,6 +3448,151 @@ static void do_displacement_eraser_brush(Sculpt *sd, Object *ob, PBVHNode **node /** \} */ +/** \name Sculpt Multires Displacement Smear Brush + * \{ */ + +static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float bstrength = clamp_f(ss->cache->bstrength, 0.0f, 1.0f); + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) + { + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.vertex, + thread_id); + + float current_disp[3]; + float current_disp_norm[3]; + float interp_limit_surface_disp[3]; + + copy_v3_v3(interp_limit_surface_disp, ss->cache->prev_displacement[vd.index]); + + switch (brush->smear_deform_type) { + case BRUSH_SMEAR_DEFORM_DRAG: + sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location); + break; + case BRUSH_SMEAR_DEFORM_PINCH: + sub_v3_v3v3(current_disp, ss->cache->location, vd.co); + break; + case BRUSH_SMEAR_DEFORM_EXPAND: + sub_v3_v3v3(current_disp, vd.co, ss->cache->location); + break; + } + + normalize_v3_v3(current_disp_norm, current_disp); + mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength); + + float weights_accum = 1.0f; + + SculptVertexNeighborIter ni; + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) { + float vertex_disp[3]; + float vertex_disp_norm[3]; + float neighbor_limit_co[3]; + SCULPT_vertex_limit_surface_get(ss, ni.vertex, neighbor_limit_co); + sub_v3_v3v3(vertex_disp, + ss->cache->limit_surface_co[ni.index], + ss->cache->limit_surface_co[vd.index]); + const float *neighbor_limit_surface_disp = ss->cache->prev_displacement[ni.index]; + normalize_v3_v3(vertex_disp_norm, vertex_disp); + if (dot_v3v3(current_disp_norm, vertex_disp_norm) < 0.0f) { + const float disp_interp = clamp_f( + -dot_v3v3(current_disp_norm, vertex_disp_norm), 0.0f, 1.0f); + madd_v3_v3fl(interp_limit_surface_disp, neighbor_limit_surface_disp, disp_interp); + weights_accum += disp_interp; + } + } + SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); + + mul_v3_fl(interp_limit_surface_disp, 1.0f / weights_accum); + + float new_co[3]; + add_v3_v3v3(new_co, ss->cache->limit_surface_co[vd.index], interp_limit_surface_disp); + interp_v3_v3v3(vd.co, vd.co, new_co, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +static void do_displacement_smear_store_prev_disp_task_cb_ex( + void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls)) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) + { + sub_v3_v3v3(ss->cache->prev_displacement[vd.index], + SCULPT_vertex_co_get(ss, vd.vertex), + ss->cache->limit_surface_co[vd.index]); + } + BKE_pbvh_vertex_iter_end; +} + +static void do_displacement_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + Brush *brush = BKE_paint_brush(&sd->paint); + SculptSession *ss = ob->sculpt; + + BKE_curvemapping_init(brush->curve); + SCULPT_vertex_random_access_ensure(ss); + + const int totvert = SCULPT_vertex_count_get(ss); + if (!ss->cache->prev_displacement) { + ss->cache->prev_displacement = MEM_malloc_arrayN( + totvert, sizeof(float[3]), "prev displacement"); + ss->cache->limit_surface_co = MEM_malloc_arrayN(totvert, sizeof(float[3]), "limit surface co"); + + for (int i = 0; i < totvert; i++) { + SculptVertRef vref = BKE_pbvh_table_index_to_vertex(ss->pbvh, i); + + SCULPT_vertex_limit_surface_get(ss, vref, ss->cache->limit_surface_co[i]); + sub_v3_v3v3(ss->cache->prev_displacement[i], + SCULPT_vertex_co_get(ss, vref), + ss->cache->limit_surface_co[i]); + } + } + /* Threaded loop over nodes. */ + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range( + 0, totnode, &data, do_displacement_smear_store_prev_disp_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_displacement_smear_brush_task_cb_ex, &settings); +} + +/** \} */ + static void do_draw_brush_task_cb_ex(void *__restrict userdata, const int n, const TaskParallelTLS *__restrict tls) @@ -4578,6 +4725,8 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata, (len_v3(grab_delta) / ss->cache->radius)) : 0.0f; + const bool do_elastic = brush->snake_hook_deform_type == BRUSH_SNAKE_HOOK_DEFORM_ELASTIC; + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; SculptBrushTest test; @@ -4585,18 +4734,28 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); + KelvinletParams params; + BKE_kelvinlet_init_params(¶ms, ss->cache->radius, bstrength, 1.0f, 0.4f); + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (sculpt_brush_test_sq_fn(&test, vd.co)) { - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask ? *vd.mask : 0.0f, - vd.vertex, - thread_id); + if (do_elastic || sculpt_brush_test_sq_fn(&test, vd.co)) { + + float fade; + if (do_elastic) { + fade = 1.0f; + } + else { + fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.vertex, + thread_id); + } mul_v3_v3fl(proxy[vd.i], grab_delta, fade); @@ -4635,6 +4794,17 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata, add_v3_v3(proxy[vd.i], delta_rotate); } + if (do_elastic) { + float disp[3]; + BKE_kelvinlet_grab_triscale(disp, ¶ms, vd.co, ss->cache->location, proxy[vd.i]); + mul_v3_fl(disp, bstrength * 20.0f); + if (vd.mask) { + mul_v3_fl(disp, 1.0f - *vd.mask); + } + mul_v3_fl(disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex)); + copy_v3_v3(proxy[vd.i], disp); + } + if (vd.mvert) { vd.mvert->flag |= ME_VERT_PBVH_UPDATE; } @@ -6021,7 +6191,8 @@ static void sculpt_topology_update(Sculpt *sd, ss->cache->radius, (brush->flag & BRUSH_FRONTFACE) != 0, (brush->falloff_shape != PAINT_FALLOFF_SHAPE_SPHERE), - symidx, brush->sculpt_tool != SCULPT_TOOL_DRAW_SHARP); + symidx, + brush->sculpt_tool != SCULPT_TOOL_DRAW_SHARP); } MEM_SAFE_FREE(nodes); @@ -6086,45 +6257,12 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe /* Build a list of all nodes that are potentially within the brush's area of influence */ - /* These brushes need to update all nodes as they are not constrained by the brush radius */ - /* Elastic deform needs all nodes to avoid artifacts as the effect of the brush is not - * constrained by the radius. */ - /* Pose needs all nodes because it applies all symmetry iterations at the same time and the IK - * chain can grow to any area of the model. */ - /* This can be optimized by filtering the nodes after calculating the chain. */ - if (ELEM(brush->sculpt_tool, - SCULPT_TOOL_ELASTIC_DEFORM, - SCULPT_TOOL_POSE, - SCULPT_TOOL_BOUNDARY)) { + if (SCULPT_tool_needs_all_pbvh_nodes(brush)) { + /* These brushes need to update all nodes as they are not constrained by the brush radius */ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); } else if (brush->sculpt_tool == SCULPT_TOOL_CLOTH) { - if (brush->cloth_simulation_area_type == BRUSH_CLOTH_SIMULATION_AREA_LOCAL) { - SculptSearchSphereData data = { - .ss = ss, - .sd = sd, - .radius_squared = square_f(ss->cache->initial_radius * (1.0 + brush->cloth_sim_limit)), - .original = false, - .ignore_fully_ineffective = false, - .center = ss->cache->initial_location, - }; - BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, &totnode); - } - if (brush->cloth_simulation_area_type == BRUSH_CLOTH_SIMULATION_AREA_DYNAMIC) { - SculptSearchSphereData data = { - .ss = ss, - .sd = sd, - .radius_squared = square_f(ss->cache->radius * (1.0 + brush->cloth_sim_limit)), - .original = false, - .ignore_fully_ineffective = false, - .center = ss->cache->location, - }; - BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, &totnode); - } - else { - /* Gobal simulation, get all nodes. */ - BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); - } + nodes = SCULPT_cloth_brush_affected_nodes_gather(ss, brush, &totnode); } else { const bool use_original = sculpt_tool_needs_original(brush->sculpt_tool) ? true : @@ -6160,6 +6298,17 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe } } + /* Initialize automasking cache. For anchored brushes with spherical falloff, we start off with + * zero radius, thus we have no pbvh nodes on the first brush step. */ + if (totnode || + ((brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) && (brush->flag & BRUSH_ANCHORED))) { + if (SCULPT_stroke_is_first_brush_step(ss->cache)) { + if (SCULPT_is_automasking_enabled(sd, ss, brush)) { + ss->cache->automasking = SCULPT_automasking_cache_init(sd, brush, ob); + } + } + } + /* Only act if some verts are inside the brush area. */ if (totnode) { float location[3]; @@ -6223,12 +6372,6 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe update_brush_local_mat(sd, ob); } - if (SCULPT_stroke_is_first_brush_step(ss->cache)) { - if (SCULPT_is_automasking_enabled(sd, ss, brush)) { - ss->cache->automasking = SCULPT_automasking_cache_init(sd, brush, ob); - } - } - if (brush->sculpt_tool == SCULPT_TOOL_POSE && SCULPT_stroke_is_first_brush_step(ss->cache)) { SCULPT_pose_brush_init(sd, ob, ss, brush); } @@ -6347,6 +6490,9 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe case SCULPT_TOOL_DISPLACEMENT_ERASER: do_displacement_eraser_brush(sd, ob, nodes, totnode); break; + case SCULPT_TOOL_DISPLACEMENT_SMEAR: + do_displacement_smear_brush(sd, ob, nodes, totnode); + break; case SCULPT_TOOL_PAINT: SCULPT_do_paint_brush(sd, ob, nodes, totnode); break; @@ -6936,6 +7082,8 @@ static const char *sculpt_tool_name(Sculpt *sd) return "Draw Face Sets"; case SCULPT_TOOL_DISPLACEMENT_ERASER: return "Multires Displacement Eraser"; + case SCULPT_TOOL_DISPLACEMENT_SMEAR: + return "Multires Displacement Smear"; case SCULPT_TOOL_PAINT: return "Paint Brush"; case SCULPT_TOOL_SMEAR: @@ -6958,6 +7106,8 @@ void SCULPT_cache_free(StrokeCache *cache) MEM_SAFE_FREE(cache->layer_displacement_factor); MEM_SAFE_FREE(cache->prev_colors); MEM_SAFE_FREE(cache->detail_directions); + MEM_SAFE_FREE(cache->prev_displacement); + MEM_SAFE_FREE(cache->limit_surface_co); if (cache->pose_ik_chain) { SCULPT_pose_ik_chain_free(cache->pose_ik_chain); @@ -7129,6 +7279,7 @@ static void sculpt_update_cache_invariants( SCULPT_TOOL_MASK, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_SIMPLIFY, + SCULPT_TOOL_DISPLACEMENT_SMEAR, SCULPT_TOOL_DISPLACEMENT_ERASER) && (sd->gravity_factor > 0.0f)); /* Get gravity vector in world space. */ @@ -9160,7 +9311,7 @@ static int sculpt_sample_color_invoke(bContext *C, static void SCULPT_OT_sample_color(wmOperatorType *ot) { /* identifiers */ - ot->name = "Sample color"; + ot->name = "Sample Color"; ot->idname = "SCULPT_OT_sample_color"; ot->description = "Sample the vertex color of the active vertex"; diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c index cd8f609b598..1eab35ae0e5 100644 --- a/source/blender/editors/sculpt_paint/sculpt_cloth.c +++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c @@ -119,6 +119,43 @@ static void cloth_brush_simulation_location_get(SculptSession *ss, copy_v3_v3(r_location, ss->cache->location); } +PBVHNode **SCULPT_cloth_brush_affected_nodes_gather(SculptSession *ss, + Brush *brush, + int *r_totnode) +{ + BLI_assert(ss->cache); + BLI_assert(brush->sculpt_tool == SCULPT_TOOL_CLOTH); + PBVHNode **nodes = NULL; + + switch (brush->cloth_simulation_area_type) { + case BRUSH_CLOTH_SIMULATION_AREA_LOCAL: { + SculptSearchSphereData data = { + .ss = ss, + .radius_squared = square_f(ss->cache->initial_radius * (1.0 + brush->cloth_sim_limit)), + .original = false, + .ignore_fully_ineffective = false, + .center = ss->cache->initial_location, + }; + BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, r_totnode); + } break; + case BRUSH_CLOTH_SIMULATION_AREA_GLOBAL: + BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, r_totnode); + break; + case BRUSH_CLOTH_SIMULATION_AREA_DYNAMIC: { + SculptSearchSphereData data = { + .ss = ss, + .radius_squared = square_f(ss->cache->radius * (1.0 + brush->cloth_sim_limit)), + .original = false, + .ignore_fully_ineffective = false, + .center = ss->cache->location, + }; + BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, r_totnode); + } break; + } + + return nodes; +} + static float cloth_brush_simulation_falloff_get(const Brush *brush, const float radius, const float location[3], diff --git a/source/blender/editors/sculpt_paint/sculpt_detail.c b/source/blender/editors/sculpt_paint/sculpt_detail.c index c044fec0d7b..0ee8114aba2 100644 --- a/source/blender/editors/sculpt_paint/sculpt_detail.c +++ b/source/blender/editors/sculpt_paint/sculpt_detail.c @@ -363,7 +363,7 @@ void SCULPT_OT_sample_detail_size(wmOperatorType *ot) 0, SHRT_MAX, "Location", - "Screen Coordinates of sampling", + "Screen coordinates of sampling", 0, SHRT_MAX); RNA_def_enum(ot->srna, diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c index 4227c14df76..0a02f8b543b 100644 --- a/source/blender/editors/sculpt_paint/sculpt_face_set.c +++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c @@ -42,6 +42,7 @@ #include "BKE_context.h" #include "BKE_customdata.h" #include "BKE_mesh.h" +#include "BKE_mesh_fair.h" #include "BKE_mesh_mapping.h" #include "BKE_multires.h" #include "BKE_node.h" @@ -1067,6 +1068,8 @@ typedef enum eSculptFaceSetEditMode { SCULPT_FACE_SET_EDIT_GROW = 0, SCULPT_FACE_SET_EDIT_SHRINK = 1, SCULPT_FACE_SET_EDIT_DELETE_GEOMETRY = 2, + SCULPT_FACE_SET_EDIT_FAIR_POSITIONS = 3, + SCULPT_FACE_SET_EDIT_FAIR_TANGENCY = 4, } eSculptFaceSetEditMode; static EnumPropertyItem prop_sculpt_face_sets_edit_types[] = { @@ -1091,6 +1094,22 @@ static EnumPropertyItem prop_sculpt_face_sets_edit_types[] = { "Delete Geometry", "Deletes the faces that are assigned to the Face Set", }, + { + SCULPT_FACE_SET_EDIT_FAIR_POSITIONS, + "FAIR_POSITIONS", + 0, + "Fair Positions", + "Creates a smooth as possible geometry patch from the Face Set minimizing changes in " + "vertex positions", + }, + { + SCULPT_FACE_SET_EDIT_FAIR_TANGENCY, + "FAIR_TANGENCY", + 0, + "Fair Tangency", + "Creates a smooth as possible geometry patch from the Face Set minimizing changes in " + "vertex tangents", + }, {0, NULL, 0, NULL, NULL}, }; @@ -1177,7 +1196,7 @@ static void sculpt_face_set_shrink(Object *ob, const bool modify_hidden) { if (ss && ss->bm) { - //XXX implement me + // XXX implement me return; } @@ -1279,6 +1298,33 @@ static void sculpt_face_set_delete_geometry(Object *ob, BM_mesh_free(bm); } +static void sculpt_face_set_edit_fair_face_set(Object *ob, + const int active_face_set_id, + const int fair_order) +{ + SculptSession *ss = ob->sculpt; + + const int totvert = SCULPT_vertex_count_get(ss); + + Mesh *mesh = ob->data; + bool *fair_vertices = MEM_malloc_arrayN(sizeof(bool), totvert, "fair vertices"); + + SCULPT_vertex_random_access_ensure(ss); + SCULPT_boundary_info_ensure(ob); + + for (int i = 0; i < totvert; i++) { + SculptVertRef vref = BKE_pbvh_table_index_to_vertex(ss->pbvh, i); + + fair_vertices[i] = !SCULPT_vertex_is_boundary(ss, vref) && + SCULPT_vertex_has_face_set(ss, vref, active_face_set_id) && + SCULPT_vertex_has_unique_face_set(ss, vref); + } + + MVert *mvert = SCULPT_mesh_deformed_mverts_get(ss); + BKE_mesh_prefair_and_fair_vertices(mesh, mvert, fair_vertices, fair_order); + MEM_freeN(fair_vertices); +} + static void sculpt_face_set_apply_edit(Object *ob, const int active_face_set_id, const int mode, @@ -1302,6 +1348,12 @@ static void sculpt_face_set_apply_edit(Object *ob, case SCULPT_FACE_SET_EDIT_DELETE_GEOMETRY: sculpt_face_set_delete_geometry(ob, ss, active_face_set_id, modify_hidden); break; + case SCULPT_FACE_SET_EDIT_FAIR_POSITIONS: + sculpt_face_set_edit_fair_face_set(ob, active_face_set_id, MESH_FAIRING_DEPTH_POSITION); + break; + case SCULPT_FACE_SET_EDIT_FAIR_TANGENCY: + sculpt_face_set_edit_fair_face_set(ob, active_face_set_id, MESH_FAIRING_DEPTH_TANGENCY); + break; } } @@ -1328,6 +1380,16 @@ static bool sculpt_face_set_edit_is_operation_valid(SculptSession *ss, return false; } } + + if (ELEM(mode, SCULPT_FACE_SET_EDIT_FAIR_POSITIONS, SCULPT_FACE_SET_EDIT_FAIR_TANGENCY)) { + if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) { + /* TODO: Multires topology representation using grids and duplicates can't be used directly + * by the fair algorithm. Multires topology needs to be exposed in a different way or + * converted to a mesh for this operation. */ + return false; + } + } + return true; } @@ -1385,11 +1447,38 @@ static void sculpt_face_set_edit_modify_face_sets(Object *ob, MEM_freeN(nodes); } +static void sculpt_face_set_edit_modify_coordinates(bContext *C, + Object *ob, + const int active_face_set, + const eSculptFaceSetEditMode mode) +{ + Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + SculptSession *ss = ob->sculpt; + PBVH *pbvh = ss->pbvh; + PBVHNode **nodes; + int totnode; + BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode); + SCULPT_undo_push_begin(ob, "face set edit"); + for (int i = 0; i < totnode; i++) { + BKE_pbvh_node_mark_update(nodes[i]); + SCULPT_undo_push_node(ob, nodes[i], SCULPT_UNDO_COORDS); + } + sculpt_face_set_apply_edit(ob, abs(active_face_set), mode, false); + + if (ss->deform_modifiers_active || ss->shapekey_active) { + SCULPT_flush_stroke_deform(sd, ob, true); + } + SCULPT_flush_update_step(C, SCULPT_UPDATE_COORDS); + SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COORDS); + SCULPT_undo_push_end(); + MEM_freeN(nodes); +} + static int sculpt_face_set_edit_invoke(bContext *C, wmOperator *op, const wmEvent *event) { Object *ob = CTX_data_active_object(C); SculptSession *ss = ob->sculpt; - Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); const int mode = RNA_enum_get(op->ptr, "mode"); const bool modify_hidden = RNA_boolean_get(op->ptr, "modify_hidden"); @@ -1418,6 +1507,10 @@ static int sculpt_face_set_edit_invoke(bContext *C, wmOperator *op, const wmEven case SCULPT_FACE_SET_EDIT_SHRINK: sculpt_face_set_edit_modify_face_sets(ob, active_face_set, mode, modify_hidden); break; + case SCULPT_FACE_SET_EDIT_FAIR_POSITIONS: + case SCULPT_FACE_SET_EDIT_FAIR_TANGENCY: + sculpt_face_set_edit_modify_coordinates(C, ob, active_face_set, mode); + break; } SCULPT_tag_update_overlays(C); diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_color.c b/source/blender/editors/sculpt_paint/sculpt_filter_color.c index ab910e3e0eb..38d2904e98a 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_color.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_color.c @@ -328,9 +328,9 @@ void SCULPT_OT_color_filter(struct wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* rna */ - RNA_def_enum(ot->srna, "type", prop_color_filter_types, COLOR_FILTER_HUE, "Filter type", ""); + RNA_def_enum(ot->srna, "type", prop_color_filter_types, COLOR_FILTER_HUE, "Filter Type", ""); RNA_def_float( - ot->srna, "strength", 1.0f, -10.0f, 10.0f, "Strength", "Filter Strength", -10.0f, 10.0f); + ot->srna, "strength", 1.0f, -10.0f, 10.0f, "Strength", "Filter strength", -10.0f, 10.0f); PropertyRNA *prop = RNA_def_float_color( ot->srna, "fill_color", 3, NULL, 0.0f, FLT_MAX, "Fill Color", "", 0.0f, 1.0f); diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c index 92142625e7b..5ce5a862cbe 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c @@ -80,12 +80,12 @@ static EnumPropertyItem prop_mask_filter_types[] = { {MASK_FILTER_CONTRAST_INCREASE, "CONTRAST_INCREASE", 0, - "Increase contrast", + "Increase Contrast", "Increase the contrast of the paint mask"}, {MASK_FILTER_CONTRAST_DECREASE, "CONTRAST_DECREASE", 0, - "Decrease contrast", + "Decrease Contrast", "Decrease the contrast of the paint mask"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c index 0001c15a31d..b8b6ebae25f 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c @@ -778,15 +778,15 @@ void SCULPT_OT_mesh_filter(struct wmOperatorType *ot) "type", prop_mesh_filter_types, MESH_FILTER_INFLATE, - "Filter type", + "Filter Type", "Operation that is going to be applied to the mesh"); RNA_def_float( - ot->srna, "strength", 1.0f, -10.0f, 10.0f, "Strength", "Filter Strength", -10.0f, 10.0f); + ot->srna, "strength", 1.0f, -10.0f, 10.0f, "Strength", "Filter strength", -10.0f, 10.0f); RNA_def_enum_flag(ot->srna, "deform_axis", prop_mesh_filter_deform_axis_items, MESH_FILTER_DEFORM_X | MESH_FILTER_DEFORM_Y | MESH_FILTER_DEFORM_Z, - "Deform axis", + "Deform Axis", "Apply the deformation in the selected axis"); RNA_def_enum(ot->srna, "orientation", diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 57a0a47df97..7aef6f71154 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -39,7 +39,6 @@ struct AutomaskingCache; struct KeyBlock; struct Object; -struct SculptPoseIKChainSegment; struct SculptUndoNode; struct bContext; @@ -436,6 +435,10 @@ void SCULPT_cloth_plane_falloff_preview_draw(const uint gpuattr, const float outline_col[3], float outline_alpha); +PBVHNode **SCULPT_cloth_brush_affected_nodes_gather(SculptSession *ss, + Brush *brush, + int *r_totnode); + BLI_INLINE bool SCULPT_is_cloth_deform_brush(const Brush *brush) { return (brush->sculpt_tool == SCULPT_TOOL_CLOTH && ELEM(brush->cloth_deform_type, @@ -447,6 +450,38 @@ BLI_INLINE bool SCULPT_is_cloth_deform_brush(const Brush *brush) brush->deform_target == BRUSH_DEFORM_TARGET_CLOTH_SIM); } +BLI_INLINE bool SCULPT_tool_needs_all_pbvh_nodes(const Brush *brush) +{ + if (brush->sculpt_tool == SCULPT_TOOL_ELASTIC_DEFORM) { + /* Elastic deformations in any brush need all nodes to avoid artifacts as the effect + * of the Kelvinlet is not constrained by the radius. */ + return true; + } + + if (brush->sculpt_tool == SCULPT_TOOL_POSE) { + /* Pose needs all nodes because it applies all symmetry iterations at the same time + * and the IK chain can grow to any area of the model. */ + /* TODO: This can be optimized by filtering the nodes after calculating the chain. */ + return true; + } + + if (brush->sculpt_tool == SCULPT_TOOL_BOUNDARY) { + /* Boundary needs all nodes because it is not possible to know where the boundary + * deformation is going to be propagated before calculating it. */ + /* TODO: after calculating the boundary info in the first iteration, it should be + * possible to get the nodes that have vertices included in any boundary deformation + * and cache them. */ + return true; + } + + if (brush->sculpt_tool == SCULPT_TOOL_SNAKE_HOOK && + brush->snake_hook_deform_type == BRUSH_SNAKE_HOOK_DEFORM_ELASTIC) { + /* Snake hook in elastic deform type has same requirements as the elastic deform tool. */ + return true; + } + return false; +} + /* Pose Brush. */ void SCULPT_do_pose_brush(struct Sculpt *sd, struct Object *ob, @@ -912,6 +947,10 @@ typedef struct StrokeCache { float (*prev_colors)[4]; + /* Multires Displacement Smear. */ + float (*prev_displacement)[3]; + float (*limit_surface_co)[3]; + /* The rest is temporary storage that isn't saved as a property */ bool first_time; /* Beginning of stroke may do some things special */ diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c index c6961cc9d4b..34617804888 100644 --- a/source/blender/editors/sound/sound_ops.c +++ b/source/blender/editors/sound/sound_ops.c @@ -52,7 +52,7 @@ #include "RNA_define.h" #include "RNA_enum_types.h" -#include "SEQ_sequencer.h" +#include "SEQ_iterator.h" #include "UI_interface.h" @@ -259,7 +259,7 @@ static void sound_update_animation_flags(Scene *scene) scene->id.tag |= LIB_TAG_DOIT; SEQ_ALL_BEGIN (scene->ed, seq) { - BKE_sequencer_recursive_apply(seq, sound_update_animation_flags_fn, scene); + SEQ_iterator_recursive_apply(seq, sound_update_animation_flags_fn, scene); } SEQ_ALL_END; @@ -518,27 +518,27 @@ static bool sound_mixdown_draw_check_prop(PointerRNA *UNUSED(ptr), static void sound_mixdown_draw(bContext *C, wmOperator *op) { static const EnumPropertyItem pcm_format_items[] = { - {AUD_FORMAT_U8, "U8", 0, "U8", "8 bit unsigned"}, - {AUD_FORMAT_S16, "S16", 0, "S16", "16 bit signed"}, + {AUD_FORMAT_U8, "U8", 0, "U8", "8-bit unsigned"}, + {AUD_FORMAT_S16, "S16", 0, "S16", "16-bit signed"}, # ifdef WITH_SNDFILE - {AUD_FORMAT_S24, "S24", 0, "S24", "24 bit signed"}, + {AUD_FORMAT_S24, "S24", 0, "S24", "24-bit signed"}, # endif - {AUD_FORMAT_S32, "S32", 0, "S32", "32 bit signed"}, - {AUD_FORMAT_FLOAT32, "F32", 0, "F32", "32 bit floating point"}, - {AUD_FORMAT_FLOAT64, "F64", 0, "F64", "64 bit floating point"}, + {AUD_FORMAT_S32, "S32", 0, "S32", "32-bit signed"}, + {AUD_FORMAT_FLOAT32, "F32", 0, "F32", "32-bit floating-point"}, + {AUD_FORMAT_FLOAT64, "F64", 0, "F64", "64-bit floating-point"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem mp3_format_items[] = { - {AUD_FORMAT_S16, "S16", 0, "S16", "16 bit signed"}, - {AUD_FORMAT_S32, "S32", 0, "S32", "32 bit signed"}, + {AUD_FORMAT_S16, "S16", 0, "S16", "16-bit signed"}, + {AUD_FORMAT_S32, "S32", 0, "S32", "32-bit signed"}, {0, NULL, 0, NULL, NULL}, }; # ifdef WITH_SNDFILE static const EnumPropertyItem flac_format_items[] = { - {AUD_FORMAT_S16, "S16", 0, "S16", "16 bit signed"}, - {AUD_FORMAT_S24, "S24", 0, "S24", "24 bit signed"}, + {AUD_FORMAT_S16, "S16", 0, "S16", "16-bit signed"}, + {AUD_FORMAT_S24, "S24", 0, "S24", "24-bit signed"}, {0, NULL, 0, NULL, NULL}, }; # endif @@ -672,12 +672,12 @@ static void SOUND_OT_mixdown(wmOperatorType *ot) { #ifdef WITH_AUDASPACE static const EnumPropertyItem format_items[] = { - {AUD_FORMAT_U8, "U8", 0, "U8", "8 bit unsigned"}, - {AUD_FORMAT_S16, "S16", 0, "S16", "16 bit signed"}, - {AUD_FORMAT_S24, "S24", 0, "S24", "24 bit signed"}, - {AUD_FORMAT_S32, "S32", 0, "S32", "32 bit signed"}, - {AUD_FORMAT_FLOAT32, "F32", 0, "F32", "32 bit floating point"}, - {AUD_FORMAT_FLOAT64, "F64", 0, "F64", "64 bit floating point"}, + {AUD_FORMAT_U8, "U8", 0, "U8", "8-bit unsigned"}, + {AUD_FORMAT_S16, "S16", 0, "S16", "16-bit signed"}, + {AUD_FORMAT_S24, "S24", 0, "S24", "24-bit signed"}, + {AUD_FORMAT_S32, "S32", 0, "S32", "32-bit signed"}, + {AUD_FORMAT_FLOAT32, "F32", 0, "F32", "32-bit floating-point"}, + {AUD_FORMAT_FLOAT64, "F64", 0, "F64", "64-bit floating-point"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c index e20be9c8328..4d5a93f75e0 100644 --- a/source/blender/editors/space_action/action_data.c +++ b/source/blender/editors/space_action/action_data.c @@ -158,7 +158,78 @@ static void actedit_change_action(bContext *C, bAction *act) RNA_property_update(C, &ptr, prop); } -/* ******************** New Action Operator *********************** */ +/* ******************** New Action Operators *********************** */ + +static void action_creation_assign(bContext *C, + bAction *action, + PointerRNA *ptr, + PropertyRNA *prop) +{ + PointerRNA idptr; + /* Set the new action. + * NOTE: we can't use actedit_change_action, as this function is also called from the NLA. */ + RNA_id_pointer_create(&action->id, &idptr); + RNA_property_pointer_set(ptr, prop, idptr, NULL); + RNA_property_update(C, ptr, prop); +} + +/** + * Stash the previously active action to prevent it from being lost. + * \return The old action if any. + */ +static bAction *action_creation_stash_old(bContext *C, PointerRNA *ptr, PropertyRNA *prop) +{ + bAction *oldact = NULL; + AnimData *adt = NULL; + + if (prop) { + /* The operator was called from a button. */ + PointerRNA oldptr; + + oldptr = RNA_property_pointer_get(ptr, prop); + oldact = (bAction *)oldptr.owner_id; + + /* stash the old action to prevent it from being lost */ + if (ptr->type == &RNA_AnimData) { + adt = ptr->data; + } + else if (ptr->type == &RNA_SpaceDopeSheetEditor) { + adt = ED_actedit_animdata_from_context(C); + } + } + else { + adt = ED_actedit_animdata_from_context(C); + oldact = adt->action; + } + + if (!adt || !oldact) { + /* Found nothing to stash in current context. */ + return NULL; + } + + /* Perform stashing operation. */ + if (BKE_nla_action_stash(adt, ID_IS_OVERRIDE_LIBRARY(ptr->owner_id))) { + /* The stash operation will remove the user already + * (and unlink the action from the AnimData action slot). + * Hence, we must unset the ref to the action in the + * action editor too (if this is where we're being called from) + * first before setting the new action once it is created, + * or else the user gets decremented twice! + */ + if (ptr->type == &RNA_SpaceDopeSheetEditor) { + SpaceAction *saction = ptr->data; + saction->action = NULL; + } + } + else { +#if 0 + printf("WARNING: Failed to stash %s. It may already exist in the NLA stack though\n", + oldact->id.name); +#endif + } + + return oldact; +} /* Criteria: * 1) There must be an dopesheet/action editor, and it must be in a mode which uses actions... @@ -207,71 +278,17 @@ static bool action_new_poll(bContext *C) static int action_new_exec(bContext *C, wmOperator *UNUSED(op)) { - PointerRNA ptr, idptr; + PointerRNA ptr; PropertyRNA *prop; - bAction *oldact = NULL; - AnimData *adt = NULL; /* hook into UI */ UI_context_active_but_prop_get_templateID(C, &ptr, &prop); - if (prop) { - /* The operator was called from a button. */ - PointerRNA oldptr; - - oldptr = RNA_property_pointer_get(&ptr, prop); - oldact = (bAction *)oldptr.owner_id; - - /* stash the old action to prevent it from being lost */ - if (ptr.type == &RNA_AnimData) { - adt = ptr.data; - } - else if (ptr.type == &RNA_SpaceDopeSheetEditor) { - adt = ED_actedit_animdata_from_context(C); - } - } - else { - adt = ED_actedit_animdata_from_context(C); - oldact = adt->action; - } - { - bAction *action = NULL; - - /* Perform stashing operation - But only if there is an action */ - if (adt && oldact) { - /* stash the action */ - if (BKE_nla_action_stash(adt)) { - /* The stash operation will remove the user already - * (and unlink the action from the AnimData action slot). - * Hence, we must unset the ref to the action in the - * action editor too (if this is where we're being called from) - * first before setting the new action once it is created, - * or else the user gets decremented twice! - */ - if (ptr.type == &RNA_SpaceDopeSheetEditor) { - SpaceAction *saction = ptr.data; - saction->action = NULL; - } - } - else { -#if 0 - printf("WARNING: Failed to stash %s. It may already exist in the NLA stack though\n", - oldact->id.name); -#endif - } - } - - /* create action */ - action = action_create_new(C, oldact); + action_creation_stash_old(C, &ptr, prop); - if (prop) { - /* set this new action - * NOTE: we can't use actedit_change_action, as this function is also called from the NLA - */ - RNA_id_pointer_create(&action->id, &idptr); - RNA_property_pointer_set(&ptr, prop, idptr, NULL); - RNA_property_update(C, &ptr, prop); - } + bAction *action = action_create_new(C, NULL); + if (prop) { + action_creation_assign(C, action, &ptr, prop); } /* set notifier that keyframes have changed */ @@ -285,7 +302,7 @@ void ACTION_OT_new(wmOperatorType *ot) /* identifiers */ ot->name = "New Action"; ot->idname = "ACTION_OT_new"; - ot->description = "Create new action"; + ot->description = "Create a new action"; /* api callbacks */ ot->exec = action_new_exec; @@ -295,6 +312,45 @@ void ACTION_OT_new(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +static int action_duplicate_assign_exec(bContext *C, wmOperator *UNUSED(op)) +{ + PointerRNA ptr; + PropertyRNA *prop; + + /* hook into UI */ + UI_context_active_but_prop_get_templateID(C, &ptr, &prop); + + bAction *old_action = action_creation_stash_old(C, &ptr, prop); + + bAction *new_action = action_create_new(C, old_action); + if (prop) { + action_creation_assign(C, new_action, &ptr, prop); + } + + /* set notifier that keyframes have changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL); + + return OPERATOR_FINISHED; +} + +/** + * Duplicate an action assigned to a templateID and update it's assignment - based on UI context. + */ +void ACTION_OT_duplicate_assign(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Duplicate & Assign Action"; + ot->idname = "ACTION_OT_duplicate_assign"; + ot->description = "Create a copy of an existing action and assign it"; + + /* api callbacks */ + ot->exec = action_duplicate_assign_exec; + ot->poll = action_new_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; +} + /* ******************* Action Push-Down Operator ******************** */ /* Criteria: @@ -339,7 +395,8 @@ static int action_pushdown_exec(bContext *C, wmOperator *op) } /* action can be safely added */ - BKE_nla_action_pushdown(adt); + const Object *ob = CTX_data_active_object(C); + BKE_nla_action_pushdown(adt, ID_IS_OVERRIDE_LIBRARY(ob)); /* Stop displaying this action in this editor * NOTE: The editor itself doesn't set a user... @@ -384,7 +441,8 @@ static int action_stash_exec(bContext *C, wmOperator *op) } /* stash the action */ - if (BKE_nla_action_stash(adt)) { + Object *ob = CTX_data_active_object(C); + if (BKE_nla_action_stash(adt, ID_IS_OVERRIDE_LIBRARY(ob))) { /* The stash operation will remove the user already, * so the flushing step later shouldn't double up * the user-count fixes. Hence, we must unset this ref @@ -486,7 +544,8 @@ static int action_stash_create_exec(bContext *C, wmOperator *op) } /* stash the action */ - if (BKE_nla_action_stash(adt)) { + Object *ob = CTX_data_active_object(C); + if (BKE_nla_action_stash(adt, ID_IS_OVERRIDE_LIBRARY(ob))) { bAction *new_action = NULL; /* Create new action not based on the old one diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c index 167215b3813..d186cafb857 100644 --- a/source/blender/editors/space_action/action_edit.c +++ b/source/blender/editors/space_action/action_edit.c @@ -1827,7 +1827,7 @@ static const EnumPropertyItem prop_actkeys_mirror_types[] = { {ACTKEYS_MIRROR_XAXIS, "XAXIS", 0, - "By Values Over Value=0", + "By Values Over Zero Value", "Flip values of selected keyframes (i.e. negative values become positive, and vice versa)"}, {ACTKEYS_MIRROR_MARKER, "MARKER", diff --git a/source/blender/editors/space_action/action_intern.h b/source/blender/editors/space_action/action_intern.h index ffe0606c98f..4bce6c62a1a 100644 --- a/source/blender/editors/space_action/action_intern.h +++ b/source/blender/editors/space_action/action_intern.h @@ -106,6 +106,7 @@ void ACTION_OT_snap(struct wmOperatorType *ot); void ACTION_OT_mirror(struct wmOperatorType *ot); void ACTION_OT_new(struct wmOperatorType *ot); +void ACTION_OT_duplicate_assign(struct wmOperatorType *ot); void ACTION_OT_unlink(struct wmOperatorType *ot); void ACTION_OT_push_down(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_action/action_ops.c b/source/blender/editors/space_action/action_ops.c index 7422c05511c..329c3a9f6f6 100644 --- a/source/blender/editors/space_action/action_ops.c +++ b/source/blender/editors/space_action/action_ops.c @@ -73,7 +73,9 @@ void action_operatortypes(void) WM_operatortype_append(ACTION_OT_copy); WM_operatortype_append(ACTION_OT_paste); + /* UI-context based operators. */ WM_operatortype_append(ACTION_OT_new); + WM_operatortype_append(ACTION_OT_duplicate_assign); WM_operatortype_append(ACTION_OT_unlink); WM_operatortype_append(ACTION_OT_push_down); diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c index ab5f1e0ab22..98e39520e99 100644 --- a/source/blender/editors/space_action/action_select.c +++ b/source/blender/editors/space_action/action_select.c @@ -1325,8 +1325,8 @@ void ACTION_OT_select_less(wmOperatorType *ot) /* defines for left-right select tool */ static const EnumPropertyItem prop_actkeys_leftright_select_types[] = { {ACTKEYS_LRSEL_TEST, "CHECK", 0, "Check if Select Left or Right", ""}, - {ACTKEYS_LRSEL_LEFT, "LEFT", 0, "Before current frame", ""}, - {ACTKEYS_LRSEL_RIGHT, "RIGHT", 0, "After current frame", ""}, + {ACTKEYS_LRSEL_LEFT, "LEFT", 0, "Before Current Frame", ""}, + {ACTKEYS_LRSEL_RIGHT, "RIGHT", 0, "After Current Frame", ""}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c index 10ce7b81954..10fa2c19919 100644 --- a/source/blender/editors/space_api/spacetypes.c +++ b/source/blender/editors/space_api/spacetypes.c @@ -40,6 +40,7 @@ #include "ED_anim_api.h" #include "ED_armature.h" +#include "ED_asset.h" #include "ED_clip.h" #include "ED_curve.h" #include "ED_fileselect.h" @@ -64,6 +65,7 @@ #include "ED_space_api.h" #include "ED_transform.h" #include "ED_userpref.h" +#include "ED_util.h" #include "ED_uvedit.h" #include "io_ops.h" @@ -105,6 +107,7 @@ void ED_spacetypes_init(void) ED_operatortypes_screen(); ED_operatortypes_anim(); ED_operatortypes_animchannels(); + ED_operatortypes_asset(); ED_operatortypes_gpencil(); ED_operatortypes_object(); ED_operatortypes_lattice(); @@ -122,6 +125,7 @@ void ED_spacetypes_init(void) ED_operatortypes_render(); ED_operatortypes_mask(); ED_operatortypes_io(); + ED_operatortypes_edutils(); ED_operatortypes_view2d(); ED_operatortypes_ui(); diff --git a/source/blender/editors/space_buttons/CMakeLists.txt b/source/blender/editors/space_buttons/CMakeLists.txt index fa3e6a51036..c71e5e49d8d 100644 --- a/source/blender/editors/space_buttons/CMakeLists.txt +++ b/source/blender/editors/space_buttons/CMakeLists.txt @@ -51,6 +51,7 @@ endif() if(WITH_EXPERIMENTAL_FEATURES) add_definitions(-DWITH_GEOMETRY_NODES) + add_definitions(-DWITH_POINT_CLOUD) add_definitions(-DWITH_HAIR_NODES) endif() diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c index 8b39995a5c9..c1f29231f96 100644 --- a/source/blender/editors/space_buttons/buttons_context.c +++ b/source/blender/editors/space_buttons/buttons_context.c @@ -246,9 +246,11 @@ static bool buttons_context_path_data(ButsContextPath *path, int type) return true; } #endif +#ifdef WITH_POINT_CLOUD if (RNA_struct_is_a(ptr->type, &RNA_PointCloud) && (type == -1 || type == OB_POINTCLOUD)) { return true; } +#endif if (RNA_struct_is_a(ptr->type, &RNA_Volume) && (type == -1 || type == OB_VOLUME)) { return true; } @@ -812,7 +814,9 @@ const char *buttons_context_dir[] = { #ifdef WITH_HAIR_NODES "hair", #endif +#ifdef WITH_POINT_CLOUD "pointcloud", +#endif "volume", NULL, }; @@ -822,6 +826,11 @@ int /*eContextResult*/ buttons_context(const bContext *C, bContextDataResult *result) { SpaceProperties *sbuts = CTX_wm_space_properties(C); + if (sbuts && sbuts->path == NULL) { + /* path is cleared for SCREEN_OT_redo_last, when global undo does a file-read which clears the + * path (see lib_link_workspace_layout_restore). */ + buttons_context_compute(C, sbuts); + } ButsContextPath *path = sbuts ? sbuts->path : NULL; if (!path) { @@ -899,10 +908,12 @@ int /*eContextResult*/ buttons_context(const bContext *C, return CTX_RESULT_OK; } #endif +#ifdef WITH_POINT_CLOUD if (CTX_data_equals(member, "pointcloud")) { set_pointer_type(path, result, &RNA_PointCloud); return CTX_RESULT_OK; } +#endif if (CTX_data_equals(member, "volume")) { set_pointer_type(path, result, &RNA_Volume); return CTX_RESULT_OK; diff --git a/source/blender/editors/space_buttons/buttons_intern.h b/source/blender/editors/space_buttons/buttons_intern.h index 0a0846cf216..74e7bc11c26 100644 --- a/source/blender/editors/space_buttons/buttons_intern.h +++ b/source/blender/editors/space_buttons/buttons_intern.h @@ -35,7 +35,6 @@ struct bContext; struct bContextDataResult; struct bNode; struct bNodeTree; -struct uiLayout; struct wmOperatorType; struct SpaceProperties_Runtime { diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c index 8bdc2ed993f..8f57abf83ae 100644 --- a/source/blender/editors/space_buttons/buttons_ops.c +++ b/source/blender/editors/space_buttons/buttons_ops.c @@ -338,7 +338,7 @@ static int file_browse_invoke(bContext *C, wmOperator *op, const wmEvent *event) is_relative = BLI_path_is_rel(str); } - if (UNLIKELY(ptr.data == &U)) { + if (UNLIKELY(ptr.data == &U || is_userdef)) { is_relative = false; } diff --git a/source/blender/editors/space_clip/clip_buttons.c b/source/blender/editors/space_clip/clip_buttons.c index a95d0e3ea88..e0f603eb3d1 100644 --- a/source/blender/editors/space_clip/clip_buttons.c +++ b/source/blender/editors/space_clip/clip_buttons.c @@ -140,6 +140,7 @@ void uiTemplateMovieClip( ptr, propname, NULL, + NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c index 3f00e3114a5..8f36ccb019a 100644 --- a/source/blender/editors/space_clip/clip_ops.c +++ b/source/blender/editors/space_clip/clip_ops.c @@ -859,7 +859,7 @@ void CLIP_OT_view_zoom_out(wmOperatorType *ot) -FLT_MAX, FLT_MAX, "Location", - "Cursor location in normalized (0.0-1.0) coordinates", + "Cursor location in normalized (0.0 to 1.0) coordinates", -10.0f, 10.0f); RNA_def_property_flag(prop, PROP_HIDDEN); diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c index a54faa41122..9b8e9e0e871 100644 --- a/source/blender/editors/space_console/space_console.c +++ b/source/blender/editors/space_console/space_console.c @@ -164,12 +164,12 @@ static bool id_drop_poll(bContext *UNUSED(C), const wmEvent *UNUSED(event), const char **UNUSED(tooltip)) { - return WM_drag_ID(drag, 0) != NULL; + return WM_drag_get_local_ID(drag, 0) != NULL; } static void id_drop_copy(wmDrag *drag, wmDropBox *drop) { - ID *id = WM_drag_ID(drag, 0); + ID *id = WM_drag_get_local_ID(drag, 0); /* copy drag path to properties */ char *text = RNA_path_full_ID_py(G_MAIN, id); diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index 4b277435f63..f2f7f9d82f9 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -25,6 +25,7 @@ #include <math.h> #include <string.h> +#include "BLI_alloca.h" #include "BLI_blenlib.h" #include "BLI_fileops_types.h" #include "BLI_math.h" @@ -134,6 +135,7 @@ static void draw_tile(int sx, int sy, int width, int height, int colorid, int sh } static void file_draw_icon(uiBlock *block, + const FileDirEntry *file, const char *path, int sx, int sy, @@ -157,8 +159,29 @@ static void file_draw_icon(uiBlock *block, UI_but_func_tooltip_set(but, file_draw_tooltip_func, BLI_strdup(path)); if (drag) { - /* path is no more static, cannot give it directly to but... */ - UI_but_drag_set_path(but, BLI_strdup(path), true); + /* TODO duplicated from file_draw_preview(). */ + ID *id; + + if ((id = filelist_file_get_id(file))) { + UI_but_drag_set_id(but, id); + } + else if (file->typeflag & FILE_TYPE_ASSET) { + ImBuf *preview_image = filelist_file_getimage(file); + char blend_path[FILE_MAX_LIBEXTRA]; + if (BLO_library_path_explode(path, blend_path, NULL, NULL)) { + UI_but_drag_set_asset(but, + file->name, + BLI_strdup(blend_path), + file->blentype, + icon, + preview_image, + UI_DPI_FAC); + } + } + else { + /* path is no more static, cannot give it directly to but... */ + UI_but_drag_set_path(but, BLI_strdup(path), true); + } } } @@ -200,6 +223,65 @@ static void file_draw_string(int sx, }); } +/** + * \param r_sx, r_sy: The lower right corner of the last line drawn. AKA the cursor position on + * completion. + */ +static void file_draw_string_multiline(int sx, + int sy, + const char *string, + int wrap_width, + int line_height, + const uchar text_col[4], + int *r_sx, + int *r_sy) +{ + rcti rect; + + if (string[0] == '\0' || wrap_width < 1) { + return; + } + + const uiStyle *style = UI_style_get(); + int font_id = style->widgetlabel.uifont_id; + int len = strlen(string); + + rctf textbox; + BLF_wordwrap(font_id, wrap_width); + BLF_enable(font_id, BLF_WORD_WRAP); + BLF_boundbox(font_id, string, len, &textbox); + BLF_disable(font_id, BLF_WORD_WRAP); + + /* no text clipping needed, UI_fontstyle_draw does it but is a bit too strict + * (for buttons it works) */ + rect.xmin = sx; + rect.xmax = sx + wrap_width; + /* Need to increase the clipping rect by one more line, since the #UI_fontstyle_draw_ex() will + * actually start drawing at (ymax - line-height). */ + rect.ymin = sy - round_fl_to_int(BLI_rctf_size_y(&textbox)) - line_height; + rect.ymax = sy; + + struct ResultBLF result; + UI_fontstyle_draw_ex(&style->widget, + &rect, + string, + text_col, + &(struct uiFontStyleDraw_Params){ + .align = UI_STYLE_TEXT_LEFT, + .word_wrap = true, + }, + len, + NULL, + NULL, + &result); + if (r_sx) { + *r_sx = result.width; + } + if (r_sy) { + *r_sy = rect.ymin + line_height; + } +} + void file_calc_previews(const bContext *C, ARegion *region) { SpaceFile *sfile = CTX_wm_space_file(C); @@ -210,6 +292,7 @@ void file_calc_previews(const bContext *C, ARegion *region) } static void file_draw_preview(uiBlock *block, + const FileDirEntry *file, const char *path, int sx, int sy, @@ -218,7 +301,6 @@ static void file_draw_preview(uiBlock *block, const int icon, FileLayout *layout, const bool is_icon, - const int typeflags, const bool drag, const bool dimmed, const bool is_link) @@ -232,7 +314,7 @@ static void file_draw_preview(uiBlock *block, float scale; int ex, ey; bool show_outline = !is_icon && - (typeflags & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_BLENDER)); + (file->typeflag & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_BLENDER)); BLI_assert(imb != NULL); @@ -273,14 +355,14 @@ static void file_draw_preview(uiBlock *block, float col[4] = {1.0f, 1.0f, 1.0f, 1.0f}; if (is_icon) { - if (typeflags & FILE_TYPE_DIR) { + if (file->typeflag & FILE_TYPE_DIR) { UI_GetThemeColor4fv(TH_ICON_FOLDER, col); } else { UI_GetThemeColor4fv(TH_TEXT, col); } } - else if (typeflags & FILE_TYPE_FTFONT) { + else if (file->typeflag & FILE_TYPE_FTFONT) { UI_GetThemeColor4fv(TH_TEXT, col); } @@ -288,7 +370,7 @@ static void file_draw_preview(uiBlock *block, col[3] *= 0.3f; } - if (!is_icon && typeflags & FILE_TYPE_BLENDERLIB) { + if (!is_icon && file->typeflag & FILE_TYPE_BLENDERLIB) { /* Datablock preview images use premultiplied alpha. */ GPU_blend(GPU_BLEND_ALPHA_PREMULT); } @@ -324,7 +406,7 @@ static void file_draw_preview(uiBlock *block, icon_color[2] = 255; } icon_x = xco + (ex / 2.0f) - (icon_size / 2.0f); - icon_y = yco + (ey / 2.0f) - (icon_size * ((typeflags & FILE_TYPE_DIR) ? 0.78f : 0.75f)); + icon_y = yco + (ey / 2.0f) - (icon_size * ((file->typeflag & FILE_TYPE_DIR) ? 0.78f : 0.75f)); UI_icon_draw_ex( icon_x, icon_y, icon, icon_aspect / U.dpi_fac, icon_opacity, 0.0f, icon_color, false); } @@ -346,13 +428,13 @@ static void file_draw_preview(uiBlock *block, /* Link to folder or non-previewed file. */ uchar icon_color[4]; UI_GetThemeColor4ubv(TH_BACK, icon_color); - icon_x = xco + ((typeflags & FILE_TYPE_DIR) ? 0.14f : 0.23f) * scaledx; - icon_y = yco + ((typeflags & FILE_TYPE_DIR) ? 0.24f : 0.14f) * scaledy; + icon_x = xco + ((file->typeflag & FILE_TYPE_DIR) ? 0.14f : 0.23f) * scaledx; + icon_y = yco + ((file->typeflag & FILE_TYPE_DIR) ? 0.24f : 0.14f) * scaledy; UI_icon_draw_ex( icon_x, icon_y, arrow, icon_aspect / U.dpi_fac * 1.8, 0.3f, 0.0f, icon_color, false); } } - else if (icon && !is_icon && !(typeflags & FILE_TYPE_FTFONT)) { + else if (icon && !is_icon && !(file->typeflag & FILE_TYPE_FTFONT)) { /* Smaller, fainter icon at bottom-left for preview image thumbnail, but not for fonts. */ float icon_x, icon_y; const uchar dark[4] = {0, 0, 0, 255}; @@ -385,8 +467,22 @@ static void file_draw_preview(uiBlock *block, /* dragregion */ if (drag) { + ID *id; + + if ((id = filelist_file_get_id(file))) { + UI_but_drag_set_id(but, id); + } /* path is no more static, cannot give it directly to but... */ - UI_but_drag_set_image(but, BLI_strdup(path), icon, imb, scale, true); + else if (file->typeflag & FILE_TYPE_ASSET) { + char blend_path[FILE_MAX_LIBEXTRA]; + if (BLO_library_path_explode(path, blend_path, NULL, NULL)) { + UI_but_drag_set_asset( + but, file->name, BLI_strdup(blend_path), file->blentype, icon, imb, scale); + } + } + else { + UI_but_drag_set_image(but, BLI_strdup(path), icon, imb, scale, true); + } } GPU_blend(GPU_BLEND_NONE); @@ -400,11 +496,12 @@ static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname) wmWindowManager *wm = CTX_wm_manager(C); SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C); ARegion *region = CTX_wm_region(C); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); - BLI_join_dirfile(orgname, sizeof(orgname), sfile->params->dir, oldname); - BLI_strncpy(filename, sfile->params->renamefile, sizeof(filename)); + BLI_join_dirfile(orgname, sizeof(orgname), params->dir, oldname); + BLI_strncpy(filename, params->renamefile, sizeof(filename)); BLI_filename_make_safe(filename); - BLI_join_dirfile(newname, sizeof(newname), sfile->params->dir, filename); + BLI_join_dirfile(newname, sizeof(newname), params->dir, filename); if (!STREQ(orgname, newname)) { if (!BLI_exists(newname)) { @@ -415,8 +512,8 @@ static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname) } else { /* If rename is successful, scroll to newly renamed entry. */ - BLI_strncpy(sfile->params->renamefile, filename, sizeof(sfile->params->renamefile)); - sfile->params->rename_flag = FILE_PARAMS_RENAME_POSTSCROLL_PENDING; + BLI_strncpy(params->renamefile, filename, sizeof(params->renamefile)); + params->rename_flag = FILE_PARAMS_RENAME_POSTSCROLL_PENDING; if (sfile->smoothscroll_timer != NULL) { WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), sfile->smoothscroll_timer); @@ -688,7 +785,7 @@ static void draw_details_columns(const FileSelectParams *params, void file_draw_list(const bContext *C, ARegion *region) { SpaceFile *sfile = CTX_wm_space_file(C); - FileSelectParams *params = ED_fileselect_get_params(sfile); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); FileLayout *layout = ED_fileselect_get_layout(sfile, region); View2D *v2d = ®ion->v2d; struct FileList *files = sfile->files; @@ -820,6 +917,7 @@ void file_draw_list(const bContext *C, ARegion *region) } file_draw_preview(block, + file, path, sx, sy, @@ -828,13 +926,13 @@ void file_draw_list(const bContext *C, ARegion *region) icon, layout, is_icon, - file->typeflag, do_drag, is_hidden, is_link); } else { file_draw_icon(block, + file, path, sx, sy - layout->tile_border_y, @@ -847,26 +945,25 @@ void file_draw_list(const bContext *C, ARegion *region) } if (file_selflag & FILE_SEL_EDITING) { - uiBut *but; const short width = (params->display == FILE_IMGDISPLAY) ? textwidth : layout->attribute_columns[COLUMN_NAME].width - ATTRIBUTE_COLUMN_PADDING; - but = uiDefBut(block, - UI_BTYPE_TEXT, - 1, - "", - sx + icon_ofs, - sy - layout->tile_h - 0.15f * UI_UNIT_X, - width - icon_ofs, - textheight, - sfile->params->renamefile, - 1.0f, - (float)sizeof(sfile->params->renamefile), - 0, - 0, - ""); + uiBut *but = uiDefBut(block, + UI_BTYPE_TEXT, + 1, + "", + sx + icon_ofs, + sy - layout->tile_h - 0.15f * UI_UNIT_X, + width - icon_ofs, + textheight, + params->renamefile, + 1.0f, + (float)sizeof(params->renamefile), + 0, + 0, + ""); UI_but_func_rename_set(but, renamebutton_cb, file); UI_but_flag_enable(but, UI_BUT_NO_UTF8); /* allow non utf8 names */ UI_but_flag_disable(but, UI_BUT_UNDO); @@ -906,3 +1003,66 @@ void file_draw_list(const bContext *C, ARegion *region) layout->curr_size = params->thumbnail_size; } + +static void file_draw_invalid_library_hint(const SpaceFile *sfile, const ARegion *region) +{ + const FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile); + + char library_ui_path[PATH_MAX]; + file_path_to_ui_path(asset_params->base_params.dir, library_ui_path, sizeof(library_ui_path)); + + uchar text_col[4]; + uchar text_alert_col[4]; + UI_GetThemeColor4ubv(TH_TEXT, text_col); + UI_GetThemeColor4ubv(TH_REDALERT, text_alert_col); + + const View2D *v2d = ®ion->v2d; + const int pad = sfile->layout->tile_border_x; + const int width = BLI_rctf_size_x(&v2d->tot) - (2 * pad); + const int line_height = sfile->layout->textheight; + int sx = v2d->tot.xmin + pad; + /* For some reason no padding needed. */ + int sy = v2d->tot.ymax; + + { + const char *message = TIP_("Library not found"); + const int draw_string_str_len = strlen(message) + 2 + sizeof(library_ui_path); + char *draw_string = alloca(draw_string_str_len); + BLI_snprintf(draw_string, draw_string_str_len, "%s: %s", message, library_ui_path); + file_draw_string_multiline(sx, sy, draw_string, width, line_height, text_alert_col, NULL, &sy); + } + + /* Next line, but separate it a bit further. */ + sy -= line_height; + + { + UI_icon_draw(sx, sy - UI_UNIT_Y, ICON_INFO); + + const char *suggestion = TIP_( + "Set up the library or edit libraries in the Preferences, File Paths section."); + file_draw_string_multiline( + sx + UI_UNIT_X, sy, suggestion, width - UI_UNIT_X, line_height, text_col, NULL, NULL); + } +} + +/** + * Draw a string hint if the file list is invalid. + * \return true if the list is invalid and a hint was drawn. + */ +bool file_draw_hint_if_invalid(const SpaceFile *sfile, const ARegion *region) +{ + FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile); + /* Only for asset browser. */ + if (!ED_fileselect_is_asset_browser(sfile)) { + return false; + } + /* Check if the library exists. */ + if ((asset_params->asset_library.type == FILE_ASSET_LIBRARY_LOCAL) || + filelist_is_dir(sfile->files, asset_params->base_params.dir)) { + return false; + } + + file_draw_invalid_library_hint(sfile, region); + + return true; +} diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h index b459c02d9e5..56fb588776e 100644 --- a/source/blender/editors/space_file/file_intern.h +++ b/source/blender/editors/space_file/file_intern.h @@ -38,6 +38,7 @@ struct View2D; void file_calc_previews(const bContext *C, ARegion *region); void file_draw_list(const bContext *C, ARegion *region); +bool file_draw_hint_if_invalid(const SpaceFile *sfile, const ARegion *region); void file_draw_check_ex(bContext *C, struct ScrArea *area); void file_draw_check(bContext *C); @@ -90,6 +91,7 @@ void file_sfile_to_operator(struct Main *bmain, struct wmOperator *op, struct Sp void file_operator_to_sfile(struct Main *bmain, struct SpaceFile *sfile, struct wmOperator *op); /* filesel.c */ +void fileselect_refresh_params(struct SpaceFile *sfile); void fileselect_file_set(SpaceFile *sfile, const int index); bool file_attribute_column_type_enabled(const FileSelectParams *params, FileAttributeColumnType column); @@ -116,3 +118,5 @@ void file_execute_region_panels_register(struct ARegionType *art); /* file_utils.c */ void file_tile_boundbox(const ARegion *region, FileLayout *layout, const int file, rcti *r_bounds); + +void file_path_to_ui_path(const char *path, char *r_pathi, int max_size); diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 93367ad3d3c..88dd82bb9ea 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -40,6 +40,7 @@ # include "BLI_winstuff.h" #endif +#include "ED_asset.h" #include "ED_fileselect.h" #include "ED_screen.h" #include "ED_select_utils.h" @@ -188,7 +189,7 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen) Main *bmain = CTX_data_main(C); FileSelect retval = FILE_SELECT_NOTHING; SpaceFile *sfile = CTX_wm_space_file(C); - FileSelectParams *params = ED_fileselect_get_params(sfile); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); int numfiles = filelist_files_ensure(sfile->files); const FileDirEntry *file; @@ -302,10 +303,10 @@ static FileSelect file_select( bContext *C, const rcti *rect, FileSelType select, bool fill, bool do_diropen) { SpaceFile *sfile = CTX_wm_space_file(C); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); FileSelect retval = FILE_SELECT_NOTHING; FileSelection sel = file_selection_get(C, rect, fill); /* get the selection */ - const FileCheckType check_type = (sfile->params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS : - CHECK_ALL; + const FileCheckType check_type = (params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS : CHECK_ALL; /* flag the files as selected in the filelist */ filelist_entries_select_index_range_set( @@ -325,7 +326,7 @@ static FileSelect file_select( } if (select != FILE_SEL_ADD && !file_is_any_selected(sfile->files)) { - sfile->params->active_file = -1; + params->active_file = -1; } else if (sel.last >= 0) { ARegion *region = CTX_wm_region(C); @@ -390,7 +391,7 @@ static int file_box_select_modal(bContext *C, wmOperator *op, const wmEvent *eve { ARegion *region = CTX_wm_region(C); SpaceFile *sfile = CTX_wm_space_file(C); - FileSelectParams *params = ED_fileselect_get_params(sfile); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); FileSelection sel; rcti rect; @@ -521,8 +522,9 @@ static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; } - if (sfile && sfile->params) { - int idx = sfile->params->highlight_file; + const FileSelectParams *params = ED_fileselect_get_active_params(sfile); + if (sfile && params) { + int idx = params->highlight_file; int numfiles = filelist_files_ensure(sfile->files); if ((idx >= 0) && (idx < numfiles)) { @@ -613,7 +615,7 @@ static bool file_walk_select_selection_set(wmWindow *win, const bool extend, const bool fill) { - FileSelectParams *params = sfile->params; + FileSelectParams *params = ED_fileselect_get_active_params(sfile); struct FileList *files = sfile->files; const int last_sel = params->active_file; /* store old value */ int active = active_old; /* could use active_old instead, just for readability */ @@ -804,7 +806,7 @@ static bool file_walk_select_do(bContext *C, static int file_walk_select_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C); - FileSelectParams *params = sfile->params; + FileSelectParams *params = ED_fileselect_get_active_params(sfile); const int direction = RNA_enum_get(op->ptr, "direction"); const bool extend = RNA_boolean_get(op->ptr, "extend"); const bool fill = RNA_boolean_get(op->ptr, "fill"); @@ -853,6 +855,7 @@ static int file_select_all_exec(bContext *C, wmOperator *op) { ScrArea *area = CTX_wm_area(C); SpaceFile *sfile = CTX_wm_space_file(C); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); FileSelection sel; const int numfiles = filelist_files_ensure(sfile->files); int action = RNA_enum_get(op->ptr, "action"); @@ -870,7 +873,7 @@ static int file_select_all_exec(bContext *C, wmOperator *op) switch (action) { case SEL_SELECT: case SEL_INVERT: { - check_type = (sfile->params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS : CHECK_FILES; + check_type = (params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS : CHECK_FILES; filesel_type = (action == SEL_INVERT) ? FILE_SEL_TOGGLE : FILE_SEL_ADD; break; } @@ -888,11 +891,11 @@ static int file_select_all_exec(bContext *C, wmOperator *op) filelist_entries_select_index_range_set( sfile->files, &sel, filesel_type, FILE_SEL_SELECTED, check_type); - sfile->params->active_file = -1; + params->active_file = -1; if (action != SEL_DESELECT) { for (int i = 0; i < numfiles; i++) { if (filelist_entry_select_index_get(sfile->files, i, check_type)) { - sfile->params->active_file = i; + params->active_file = i; break; } } @@ -928,6 +931,7 @@ void FILE_OT_select_all(wmOperatorType *ot) /* Note we could get rid of this one, but it's used by some addon so... * Does not hurt keeping it around for now. */ +/* TODO disallow bookmark editing in assets mode? */ static int bookmark_select_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); @@ -935,8 +939,8 @@ static int bookmark_select_exec(bContext *C, wmOperator *op) PropertyRNA *prop; if ((prop = RNA_struct_find_property(op->ptr, "dir"))) { + FileSelectParams *params = ED_fileselect_get_active_params(sfile); char entry[256]; - FileSelectParams *params = sfile->params; RNA_property_string_get(op->ptr, prop, entry); BLI_strncpy(params->dir, entry, sizeof(params->dir)); @@ -963,7 +967,7 @@ void FILE_OT_select_bookmark(wmOperatorType *ot) ot->poll = ED_operator_file_active; /* properties */ - prop = RNA_def_string(ot->srna, "dir", NULL, FILE_MAXDIR, "Dir", ""); + prop = RNA_def_string(ot->srna, "dir", NULL, FILE_MAXDIR, "Directory", ""); RNA_def_property_flag(prop, PROP_SKIP_SAVE); } @@ -978,7 +982,7 @@ static int bookmark_add_exec(bContext *C, wmOperator *UNUSED(op)) ScrArea *area = CTX_wm_area(C); SpaceFile *sfile = CTX_wm_space_file(C); struct FSMenu *fsmenu = ED_fsmenu_get(); - struct FileSelectParams *params = ED_fileselect_get_params(sfile); + struct FileSelectParams *params = ED_fileselect_get_active_params(sfile); if (params->dir[0] != '\0') { char name[FILE_MAX]; @@ -1274,7 +1278,7 @@ int file_highlight_set(SpaceFile *sfile, ARegion *region, int mx, int my) } numfiles = filelist_files_ensure(sfile->files); - params = ED_fileselect_get_params(sfile); + params = ED_fileselect_get_active_params(sfile); origfile = params->highlight_file; @@ -1345,20 +1349,21 @@ static int file_column_sort_ui_context_invoke(bContext *C, if (file_attribute_column_header_is_inside( ®ion->v2d, sfile->layout, event->mval[0], event->mval[1])) { + FileSelectParams *params = ED_fileselect_get_active_params(sfile); const FileAttributeColumnType column_type = file_attribute_column_type_find_isect( - ®ion->v2d, sfile->params, sfile->layout, event->mval[0]); + ®ion->v2d, params, sfile->layout, event->mval[0]); if (column_type != COLUMN_NONE) { const FileAttributeColumn *column = &sfile->layout->attribute_columns[column_type]; BLI_assert(column->sort_type != FILE_SORT_DEFAULT); - if (sfile->params->sort == column->sort_type) { + if (params->sort == column->sort_type) { /* Already sorting by selected column -> toggle sort invert (three state logic). */ - sfile->params->flag ^= FILE_SORT_INVERT; + params->flag ^= FILE_SORT_INVERT; } else { - sfile->params->sort = column->sort_type; - sfile->params->flag &= ~FILE_SORT_INVERT; + params->sort = column->sort_type; + params->flag &= ~FILE_SORT_INVERT; } WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); @@ -1433,10 +1438,11 @@ void FILE_OT_cancel(struct wmOperatorType *ot) void file_sfile_to_operator_ex(Main *bmain, wmOperator *op, SpaceFile *sfile, char *filepath) { + FileSelectParams *params = ED_fileselect_get_active_params(sfile); PropertyRNA *prop; /* XXX, not real length */ - BLI_join_dirfile(filepath, FILE_MAX, sfile->params->dir, sfile->params->file); + BLI_join_dirfile(filepath, FILE_MAX, params->dir, params->file); if ((prop = RNA_struct_find_property(op->ptr, "relative_path"))) { if (RNA_property_boolean_get(op->ptr, prop)) { @@ -1445,10 +1451,10 @@ void file_sfile_to_operator_ex(Main *bmain, wmOperator *op, SpaceFile *sfile, ch } if ((prop = RNA_struct_find_property(op->ptr, "filename"))) { - RNA_property_string_set(op->ptr, prop, sfile->params->file); + RNA_property_string_set(op->ptr, prop, params->file); } if ((prop = RNA_struct_find_property(op->ptr, "directory"))) { - RNA_property_string_set(op->ptr, prop, sfile->params->dir); + RNA_property_string_set(op->ptr, prop, params->dir); } if ((prop = RNA_struct_find_property(op->ptr, "filepath"))) { RNA_property_string_set(op->ptr, prop, filepath); @@ -1479,7 +1485,7 @@ void file_sfile_to_operator_ex(Main *bmain, wmOperator *op, SpaceFile *sfile, ch * files selected */ if (0 == num_files) { RNA_property_collection_add(op->ptr, prop, &itemptr); - RNA_string_set(&itemptr, "name", sfile->params->file); + RNA_string_set(&itemptr, "name", params->file); } } @@ -1500,7 +1506,7 @@ void file_sfile_to_operator_ex(Main *bmain, wmOperator *op, SpaceFile *sfile, ch * directory selected */ if (0 == num_dirs) { RNA_property_collection_add(op->ptr, prop, &itemptr); - RNA_string_set(&itemptr, "name", sfile->params->dir); + RNA_string_set(&itemptr, "name", params->dir); } } } @@ -1514,30 +1520,28 @@ void file_sfile_to_operator(Main *bmain, wmOperator *op, SpaceFile *sfile) void file_operator_to_sfile(Main *bmain, SpaceFile *sfile, wmOperator *op) { + FileSelectParams *params = ED_fileselect_get_active_params(sfile); PropertyRNA *prop; /* If neither of the above are set, split the filepath back */ if ((prop = RNA_struct_find_property(op->ptr, "filepath"))) { char filepath[FILE_MAX]; RNA_property_string_get(op->ptr, prop, filepath); - BLI_split_dirfile(filepath, - sfile->params->dir, - sfile->params->file, - sizeof(sfile->params->dir), - sizeof(sfile->params->file)); + BLI_split_dirfile( + filepath, params->dir, params->file, sizeof(params->dir), sizeof(params->file)); } else { if ((prop = RNA_struct_find_property(op->ptr, "filename"))) { - RNA_property_string_get(op->ptr, prop, sfile->params->file); + RNA_property_string_get(op->ptr, prop, params->file); } if ((prop = RNA_struct_find_property(op->ptr, "directory"))) { - RNA_property_string_get(op->ptr, prop, sfile->params->dir); + RNA_property_string_get(op->ptr, prop, params->dir); } } /* we could check for relative_path property which is used when converting * in the other direction but doesn't hurt to do this every time */ - BLI_path_abs(sfile->params->dir, BKE_main_blendfile_path(bmain)); + BLI_path_abs(params->dir, BKE_main_blendfile_path(bmain)); /* XXX, files and dirs updates missing, not really so important though */ } @@ -1547,21 +1551,19 @@ void file_operator_to_sfile(Main *bmain, SpaceFile *sfile, wmOperator *op) */ void file_sfile_filepath_set(SpaceFile *sfile, const char *filepath) { + FileSelectParams *params = ED_fileselect_get_active_params(sfile); BLI_assert(BLI_exists(filepath)); if (BLI_is_dir(filepath)) { - BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir)); + BLI_strncpy(params->dir, filepath, sizeof(params->dir)); } else { - if ((sfile->params->flag & FILE_DIRSEL_ONLY) == 0) { - BLI_split_dirfile(filepath, - sfile->params->dir, - sfile->params->file, - sizeof(sfile->params->dir), - sizeof(sfile->params->file)); + if ((params->flag & FILE_DIRSEL_ONLY) == 0) { + BLI_split_dirfile( + filepath, params->dir, params->file, sizeof(params->dir), sizeof(params->file)); } else { - BLI_split_dir_part(filepath, sfile->params->dir, sizeof(sfile->params->dir)); + BLI_split_dir_part(filepath, params->dir, sizeof(params->dir)); } } } @@ -1605,9 +1607,10 @@ void file_draw_check_cb(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2)) bool file_draw_check_exists(SpaceFile *sfile) { if (sfile->op) { /* fails on reload */ - if (sfile->params && (sfile->params->flag & FILE_CHECK_EXISTING)) { + const FileSelectParams *params = ED_fileselect_get_active_params(sfile); + if (params && (params->flag & FILE_CHECK_EXISTING)) { char filepath[FILE_MAX]; - BLI_join_dirfile(filepath, sizeof(filepath), sfile->params->dir, sfile->params->file); + BLI_join_dirfile(filepath, sizeof(filepath), params->dir, params->file); if (BLI_is_file(filepath)) { return true; } @@ -1628,21 +1631,22 @@ static int file_exec(bContext *C, wmOperator *exec_op) Main *bmain = CTX_data_main(C); wmWindowManager *wm = CTX_wm_manager(C); SpaceFile *sfile = CTX_wm_space_file(C); - struct FileDirEntry *file = filelist_file(sfile->files, sfile->params->active_file); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); + struct FileDirEntry *file = filelist_file(sfile->files, params->active_file); char filepath[FILE_MAX]; if (file && file->redirection_path) { /* redirection_path is an absolute path that takes precedence - * over using sfile->params->dir + sfile->params->file. */ + * over using params->dir + params->file. */ BLI_split_dirfile(file->redirection_path, - sfile->params->dir, - sfile->params->file, - sizeof(sfile->params->dir), - sizeof(sfile->params->file)); + params->dir, + params->file, + sizeof(params->dir), + sizeof(params->file)); /* Update relpath with redirected filename as well so that the alternative - * combination of sfile->params->dir + relpath remains valid as well. */ + * combination of params->dir + relpath remains valid as well. */ MEM_freeN(file->relpath); - file->relpath = BLI_strdup(sfile->params->file); + file->relpath = BLI_strdup(params->file); } /* directory change */ @@ -1652,12 +1656,12 @@ static int file_exec(bContext *C, wmOperator *exec_op) } if (FILENAME_IS_PARENT(file->relpath)) { - BLI_path_parent_dir(sfile->params->dir); + BLI_path_parent_dir(params->dir); } else { - BLI_path_normalize(BKE_main_blendfile_path(bmain), sfile->params->dir); - BLI_path_append(sfile->params->dir, sizeof(sfile->params->dir) - 1, file->relpath); - BLI_path_slash_ensure(sfile->params->dir); + BLI_path_normalize(BKE_main_blendfile_path(bmain), params->dir); + BLI_path_append(params->dir, sizeof(params->dir) - 1, file->relpath); + BLI_path_slash_ensure(params->dir); } ED_file_change_dir(C); } @@ -1685,10 +1689,10 @@ static int file_exec(bContext *C, wmOperator *exec_op) file_sfile_to_operator_ex(bmain, op, sfile, filepath); - if (BLI_exists(sfile->params->dir)) { + if (BLI_exists(params->dir)) { fsmenu_insert_entry(ED_fsmenu_get(), FS_CATEGORY_RECENT, - sfile->params->dir, + params->dir, NULL, ICON_FILE_FOLDER, FS_INSERT_SAVE | FS_INSERT_FIRST); @@ -1792,15 +1796,16 @@ static int file_parent_exec(bContext *C, wmOperator *UNUSED(unused)) { Main *bmain = CTX_data_main(C); SpaceFile *sfile = CTX_wm_space_file(C); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); - if (sfile->params) { - if (BLI_path_parent_dir(sfile->params->dir)) { - BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), sfile->params->dir); + if (params) { + if (BLI_path_parent_dir(params->dir)) { + BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir); ED_file_change_dir(C); - if (sfile->params->recursion_level > 1) { + if (params->recursion_level > 1) { /* Disable 'dirtree' recursion when going up in tree. */ - sfile->params->recursion_level = 0; - filelist_setrecursion(sfile->files, sfile->params->recursion_level); + params->recursion_level = 0; + filelist_setrecursion(sfile->files, params->recursion_level); } WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); } @@ -1830,15 +1835,12 @@ void FILE_OT_parent(struct wmOperatorType *ot) static int file_previous_exec(bContext *C, wmOperator *UNUSED(op)) { SpaceFile *sfile = CTX_wm_space_file(C); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); - if (sfile->params) { - if (!sfile->folders_next) { - sfile->folders_next = folderlist_new(); - } - - folderlist_pushdir(sfile->folders_next, sfile->params->dir); - folderlist_popdir(sfile->folders_prev, sfile->params->dir); - folderlist_pushdir(sfile->folders_next, sfile->params->dir); + if (params) { + folderlist_pushdir(sfile->folders_next, params->dir); + folderlist_popdir(sfile->folders_prev, params->dir); + folderlist_pushdir(sfile->folders_next, params->dir); ED_file_change_dir(C); } @@ -1868,16 +1870,13 @@ void FILE_OT_previous(struct wmOperatorType *ot) static int file_next_exec(bContext *C, wmOperator *UNUSED(unused)) { SpaceFile *sfile = CTX_wm_space_file(C); - if (sfile->params) { - if (!sfile->folders_next) { - sfile->folders_next = folderlist_new(); - } - - folderlist_pushdir(sfile->folders_prev, sfile->params->dir); - folderlist_popdir(sfile->folders_next, sfile->params->dir); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); + if (params) { + folderlist_pushdir(sfile->folders_prev, params->dir); + folderlist_popdir(sfile->folders_next, params->dir); /* update folders_prev so we can check for it in #folderlist_clear_next() */ - folderlist_pushdir(sfile->folders_prev, sfile->params->dir); + folderlist_pushdir(sfile->folders_prev, params->dir); ED_file_change_dir(C); } @@ -1923,7 +1922,7 @@ static int file_smoothscroll_invoke(bContext *C, wmOperator *UNUSED(op), const w /* Due to async nature of file listing, we may execute this code before `file_refresh()` * editing entry is available in our listing, * so we also have to handle switching to rename mode here. */ - FileSelectParams *params = ED_fileselect_get_params(sfile); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); if ((params->rename_flag & (FILE_PARAMS_RENAME_PENDING | FILE_PARAMS_RENAME_POSTSCROLL_PENDING)) != 0) { file_params_renamefile_activate(sfile, params); @@ -2175,9 +2174,10 @@ static int file_directory_new_exec(bContext *C, wmOperator *op) wmWindowManager *wm = CTX_wm_manager(C); SpaceFile *sfile = CTX_wm_space_file(C); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); const bool do_diropen = RNA_boolean_get(op->ptr, "open"); - if (!sfile->params) { + if (!params) { BKE_report(op->reports, RPT_WARNING, "No parent directory given"); return OPERATOR_CANCELLED; } @@ -2193,7 +2193,7 @@ static int file_directory_new_exec(bContext *C, wmOperator *op) if (generate_name) { /* create a new, non-existing folder name */ - if (!new_folder_path(sfile->params->dir, path, name)) { + if (!new_folder_path(params->dir, path, name)) { BKE_report(op->reports, RPT_ERROR, "Could not create new folder name"); return OPERATOR_CANCELLED; } @@ -2226,8 +2226,8 @@ static int file_directory_new_exec(bContext *C, wmOperator *op) /* If we don't enter the directory directly, remember file to jump into editing. */ if (do_diropen == false) { - BLI_strncpy(sfile->params->renamefile, name, FILE_MAXFILE); - sfile->params->rename_flag = FILE_PARAMS_RENAME_PENDING; + BLI_strncpy(params->renamefile, name, FILE_MAXFILE); + params->rename_flag = FILE_PARAMS_RENAME_PENDING; } /* set timer to smoothly view newly generated file */ @@ -2242,7 +2242,7 @@ static int file_directory_new_exec(bContext *C, wmOperator *op) ED_fileselect_clear(wm, CTX_data_scene(C), sfile); if (do_diropen) { - BLI_strncpy(sfile->params->dir, path, sizeof(sfile->params->dir)); + BLI_strncpy(params->dir, path, sizeof(params->dir)); ED_file_change_dir(C); } @@ -2284,38 +2284,37 @@ static void file_expand_directory(bContext *C) { Main *bmain = CTX_data_main(C); SpaceFile *sfile = CTX_wm_space_file(C); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); - if (sfile->params) { - if (BLI_path_is_rel(sfile->params->dir)) { + if (params) { + if (BLI_path_is_rel(params->dir)) { /* Use of 'default' folder here is just to avoid an error message on '//' prefix. */ - BLI_path_abs(sfile->params->dir, + BLI_path_abs(params->dir, G.relbase_valid ? BKE_main_blendfile_path(bmain) : BKE_appdir_folder_default()); } - else if (sfile->params->dir[0] == '~') { - char tmpstr[sizeof(sfile->params->dir) - 1]; - BLI_strncpy(tmpstr, sfile->params->dir + 1, sizeof(tmpstr)); - BLI_join_dirfile( - sfile->params->dir, sizeof(sfile->params->dir), BKE_appdir_folder_default(), tmpstr); + else if (params->dir[0] == '~') { + char tmpstr[sizeof(params->dir) - 1]; + BLI_strncpy(tmpstr, params->dir + 1, sizeof(tmpstr)); + BLI_join_dirfile(params->dir, sizeof(params->dir), BKE_appdir_folder_default(), tmpstr); } - else if (sfile->params->dir[0] == '\0') + else if (params->dir[0] == '\0') #ifndef WIN32 { - sfile->params->dir[0] = '/'; - sfile->params->dir[1] = '\0'; + params->dir[0] = '/'; + params->dir[1] = '\0'; } #else { - BLI_windows_get_default_root_dir(sfile->params->dir); + BLI_windows_get_default_root_dir(params->dir); } /* change "C:" --> "C:\", T28102. */ - else if ((isalpha(sfile->params->dir[0]) && (sfile->params->dir[1] == ':')) && - (sfile->params->dir[2] == '\0')) { - sfile->params->dir[2] = '\\'; - sfile->params->dir[3] = '\0'; + else if ((isalpha(params->dir[0]) && (params->dir[1] == ':')) && (params->dir[2] == '\0')) { + params->dir[2] = '\\'; + params->dir[3] = '\0'; } - else if (BLI_path_is_unc(sfile->params->dir)) { - BLI_path_normalize_unc(sfile->params->dir, FILE_MAX_LIBEXTRA); + else if (BLI_path_is_unc(params->dir)) { + BLI_path_normalize_unc(params->dir, FILE_MAX_LIBEXTRA); } #endif } @@ -2343,46 +2342,44 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN { Main *bmain = CTX_data_main(C); SpaceFile *sfile = CTX_wm_space_file(C); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); - if (sfile->params) { - char old_dir[sizeof(sfile->params->dir)]; + if (params) { + char old_dir[sizeof(params->dir)]; - BLI_strncpy(old_dir, sfile->params->dir, sizeof(old_dir)); + BLI_strncpy(old_dir, params->dir, sizeof(old_dir)); file_expand_directory(C); /* special case, user may have pasted a filepath into the directory */ - if (!filelist_is_dir(sfile->files, sfile->params->dir)) { + if (!filelist_is_dir(sfile->files, params->dir)) { char tdir[FILE_MAX_LIBEXTRA]; char *group, *name; - if (BLI_is_file(sfile->params->dir)) { - char path[sizeof(sfile->params->dir)]; - BLI_strncpy(path, sfile->params->dir, sizeof(path)); - BLI_split_dirfile(path, - sfile->params->dir, - sfile->params->file, - sizeof(sfile->params->dir), - sizeof(sfile->params->file)); + if (BLI_is_file(params->dir)) { + char path[sizeof(params->dir)]; + BLI_strncpy(path, params->dir, sizeof(path)); + BLI_split_dirfile( + path, params->dir, params->file, sizeof(params->dir), sizeof(params->file)); } - else if (BLO_library_path_explode(sfile->params->dir, tdir, &group, &name)) { + else if (BLO_library_path_explode(params->dir, tdir, &group, &name)) { if (group) { BLI_path_append(tdir, sizeof(tdir), group); } - BLI_strncpy(sfile->params->dir, tdir, sizeof(sfile->params->dir)); + BLI_strncpy(params->dir, tdir, sizeof(params->dir)); if (name) { - BLI_strncpy(sfile->params->file, name, sizeof(sfile->params->file)); + BLI_strncpy(params->file, name, sizeof(params->file)); } else { - sfile->params->file[0] = '\0'; + params->file[0] = '\0'; } } } - BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), sfile->params->dir); + BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir); - if (filelist_is_dir(sfile->files, sfile->params->dir)) { - if (!STREQ(sfile->params->dir, old_dir)) { /* Avoids flickering when nothing's changed. */ + if (filelist_is_dir(sfile->files, params->dir)) { + if (!STREQ(params->dir, old_dir)) { /* Avoids flickering when nothing's changed. */ /* if directory exists, enter it immediately */ ED_file_change_dir(C); } @@ -2392,10 +2389,10 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN /* UI_textbutton_activate_but(C, but); */ } #if defined(WIN32) - else if (!can_create_dir(sfile->params->dir)) { + else if (!can_create_dir(params->dir)) { const char *lastdir = folderlist_peeklastdir(sfile->folders_prev); if (lastdir) { - BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir)); + BLI_strncpy(params->dir, lastdir, sizeof(params->dir)); } } #endif @@ -2405,21 +2402,21 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN /* If we are 'inside' a blend library, we cannot do anything... */ if (lastdir && BLO_library_path_explode(lastdir, tdir, NULL, NULL)) { - BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir)); + BLI_strncpy(params->dir, lastdir, sizeof(params->dir)); } else { /* if not, ask to create it and enter if confirmed */ wmOperatorType *ot = WM_operatortype_find("FILE_OT_directory_new", false); PointerRNA ptr; WM_operator_properties_create_ptr(&ptr, ot); - RNA_string_set(&ptr, "directory", sfile->params->dir); + RNA_string_set(&ptr, "directory", params->dir); RNA_boolean_set(&ptr, "open", true); /* Enable confirmation prompt, else it's too easy * to accidentally create new directories. */ RNA_boolean_set(&ptr, "confirm", true); if (lastdir) { - BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir)); + BLI_strncpy(params->dir, lastdir, sizeof(params->dir)); } WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); @@ -2435,39 +2432,39 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg { Main *bmain = CTX_data_main(C); SpaceFile *sfile = CTX_wm_space_file(C); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); uiBut *but = arg_but; char matched_file[FILE_MAX]; - char filepath[sizeof(sfile->params->dir)]; - if (sfile->params) { + if (params) { + char filepath[sizeof(params->dir)]; int matches; matched_file[0] = '\0'; filepath[0] = '\0'; file_expand_directory(C); - matches = file_select_match(sfile, sfile->params->file, matched_file); + matches = file_select_match(sfile, params->file, matched_file); /* *After* file_select_match! */ - BLI_filename_make_safe(sfile->params->file); + BLI_filename_make_safe(params->file); if (matches) { /* replace the pattern (or filename that the user typed in, * with the first selected file of the match */ - BLI_strncpy(sfile->params->file, matched_file, sizeof(sfile->params->file)); + BLI_strncpy(params->file, matched_file, sizeof(params->file)); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); } if (matches == 1) { - BLI_join_dirfile( - filepath, sizeof(sfile->params->dir), sfile->params->dir, sfile->params->file); + BLI_join_dirfile(filepath, sizeof(params->dir), params->dir, params->file); /* if directory, open it and empty filename field */ if (filelist_is_dir(sfile->files, filepath)) { BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), filepath); - BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir)); - sfile->params->file[0] = '\0'; + BLI_strncpy(params->dir, filepath, sizeof(params->dir)); + params->file[0] = '\0'; ED_file_change_dir(C); UI_textbutton_activate_but(C, but); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); @@ -2489,9 +2486,10 @@ static int file_hidedot_exec(bContext *C, wmOperator *UNUSED(unused)) { wmWindowManager *wm = CTX_wm_manager(C); SpaceFile *sfile = CTX_wm_space_file(C); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); - if (sfile->params) { - sfile->params->flag ^= FILE_HIDE_DOT; + if (params) { + params->flag ^= FILE_HIDE_DOT; ED_fileselect_clear(wm, CTX_data_scene(C), sfile); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); } @@ -2525,7 +2523,8 @@ static bool file_filenum_poll(bContext *C) return false; } - return sfile->params && (sfile->params->flag & FILE_CHECK_EXISTING); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); + return params && (params->flag & FILE_CHECK_EXISTING); } /** @@ -2563,11 +2562,12 @@ static void filenum_newname(char *name, size_t name_size, int add) static int file_filenum_exec(bContext *C, wmOperator *op) { SpaceFile *sfile = CTX_wm_space_file(C); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); ScrArea *area = CTX_wm_area(C); int inc = RNA_int_get(op->ptr, "increment"); - if (sfile->params && (inc != 0)) { - filenum_newname(sfile->params->file, sizeof(sfile->params->file), inc); + if (params && (inc != 0)) { + filenum_newname(params->file, sizeof(params->file), inc); ED_area_tag_redraw(area); file_draw_check(C); // WM_event_add_notifier(C, NC_WINDOW, NULL); @@ -2606,12 +2606,14 @@ static void file_rename_state_activate(SpaceFile *sfile, int file_idx, bool requ if ((require_selected == false) || (filelist_entry_select_get(sfile->files, file, CHECK_ALL) & FILE_SEL_SELECTED)) { + FileSelectParams *params = ED_fileselect_get_active_params(sfile); + filelist_entry_select_index_set( sfile->files, file_idx, FILE_SEL_ADD, FILE_SEL_EDITING, CHECK_ALL); - BLI_strncpy(sfile->params->renamefile, file->relpath, FILE_MAXFILE); + BLI_strncpy(params->renamefile, file->relpath, FILE_MAXFILE); /* We can skip the pending state, * as we can directly set FILE_SEL_EDITING on the expected entry here. */ - sfile->params->rename_flag = FILE_PARAMS_RENAME_ACTIVE; + params->rename_flag = FILE_PARAMS_RENAME_ACTIVE; } } } @@ -2620,9 +2622,10 @@ static int file_rename_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent { ScrArea *area = CTX_wm_area(C); SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); - if (sfile->params) { - file_rename_state_activate(sfile, sfile->params->active_file, true); + if (params) { + file_rename_state_activate(sfile, params->active_file, true); ED_area_tag_redraw(area); } @@ -2633,9 +2636,10 @@ static int file_rename_exec(bContext *C, wmOperator *UNUSED(op)) { ScrArea *area = CTX_wm_area(C); SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); - if (sfile->params) { - file_rename_state_activate(sfile, sfile->params->highlight_file, false); + if (params) { + file_rename_state_activate(sfile, params->highlight_file, false); ED_area_tag_redraw(area); } @@ -2665,8 +2669,9 @@ static bool file_delete_poll(bContext *C) { bool poll = ED_operator_file_active(C); SpaceFile *sfile = CTX_wm_space_file(C); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); - if (sfile && sfile->params) { + if (sfile && params) { char dir[FILE_MAX_LIBEXTRA]; int numfiles = filelist_files_ensure(sfile->files); int i; @@ -2691,10 +2696,34 @@ static bool file_delete_poll(bContext *C) return poll; } +static bool file_delete_single(const FileSelectParams *params, + FileDirEntry *file, + const char **r_error_message) +{ + if (file->typeflag & FILE_TYPE_ASSET) { + ID *id = filelist_file_get_id(file); + if (!id) { + *r_error_message = "File is not a local data-block asset."; + return false; + } + ED_asset_clear_id(id); + } + else { + char str[FILE_MAX]; + BLI_join_dirfile(str, sizeof(str), params->dir, file->relpath); + if (BLI_delete_soft(str, r_error_message) != 0 || BLI_exists(str)) { + return false; + } + } + + return true; +} + static int file_delete_exec(bContext *C, wmOperator *op) { wmWindowManager *wm = CTX_wm_manager(C); SpaceFile *sfile = CTX_wm_space_file(C); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); int numfiles = filelist_files_ensure(sfile->files); const char *error_message = NULL; @@ -2703,9 +2732,7 @@ static int file_delete_exec(bContext *C, wmOperator *op) for (int i = 0; i < numfiles; i++) { if (filelist_entry_select_index_get(sfile->files, i, CHECK_ALL)) { FileDirEntry *file = filelist_file(sfile->files, i); - char str[FILE_MAX]; - BLI_join_dirfile(str, sizeof(str), sfile->params->dir, file->relpath); - if (BLI_delete_soft(str, &error_message) != 0 || BLI_exists(str)) { + if (!file_delete_single(params, file, &error_message)) { report_error = true; } } @@ -2751,12 +2778,20 @@ void FILE_OT_delete(struct wmOperatorType *ot) static int file_start_filter_exec(bContext *C, wmOperator *UNUSED(op)) { ScrArea *area = CTX_wm_area(C); - ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_UI); - SpaceFile *sf = CTX_wm_space_file(C); + SpaceFile *sfile = CTX_wm_space_file(C); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); ARegion *region_ctx = CTX_wm_region(C); - CTX_wm_region_set(C, region); - UI_textbutton_activate_rna(C, region, sf->params, "filter_search"); + + if (area) { + LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { + CTX_wm_region_set(C, region); + if (UI_textbutton_activate_rna(C, region, params, "filter_search")) { + break; + } + } + } + CTX_wm_region_set(C, region_ctx); return OPERATOR_FINISHED; diff --git a/source/blender/editors/space_file/file_panels.c b/source/blender/editors/space_file/file_panels.c index 22d206c0a70..411f99cc3b4 100644 --- a/source/blender/editors/space_file/file_panels.c +++ b/source/blender/editors/space_file/file_panels.c @@ -132,7 +132,7 @@ static void file_panel_execution_buttons_draw(const bContext *C, Panel *panel) { bScreen *screen = CTX_wm_screen(C); SpaceFile *sfile = CTX_wm_space_file(C); - FileSelectParams *params = ED_fileselect_get_params(sfile); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); uiBlock *block = uiLayoutGetBlock(panel->layout); uiBut *but; uiLayout *row; @@ -180,11 +180,16 @@ static void file_panel_execution_buttons_draw(const bContext *C, Panel *panel) UI_but_funcN_set(but, file_filename_enter_handle, NULL, but); if (params->flag & FILE_CHECK_EXISTING) { - but_extra_rna_ptr = UI_but_extra_operator_icon_add( + uiButExtraOpIcon *extra_icon; + + extra_icon = UI_but_extra_operator_icon_add( but, "FILE_OT_filenum", WM_OP_EXEC_REGION_WIN, ICON_REMOVE); + but_extra_rna_ptr = UI_but_extra_operator_icon_opptr_get(extra_icon); RNA_int_set(but_extra_rna_ptr, "increment", -1); - but_extra_rna_ptr = UI_but_extra_operator_icon_add( + + extra_icon = UI_but_extra_operator_icon_add( but, "FILE_OT_filenum", WM_OP_EXEC_REGION_WIN, ICON_ADD); + but_extra_rna_ptr = UI_but_extra_operator_icon_opptr_get(extra_icon); RNA_int_set(but_extra_rna_ptr, "increment", 1); } diff --git a/source/blender/editors/space_file/file_utils.c b/source/blender/editors/space_file/file_utils.c index 452f2f704cf..9d85996c559 100644 --- a/source/blender/editors/space_file/file_utils.c +++ b/source/blender/editors/space_file/file_utils.c @@ -18,12 +18,14 @@ * \ingroup spfile */ +#include "BLI_fileops.h" #include "BLI_listbase.h" +#include "BLI_path_util.h" #include "BLI_rect.h" - -#include "BLO_readfile.h" +#include "BLI_string.h" #include "BKE_context.h" +#include "BLO_readfile.h" #include "ED_fileselect.h" #include "ED_screen.h" @@ -44,3 +46,14 @@ void file_tile_boundbox(const ARegion *region, FileLayout *layout, const int fil ymax - layout->tile_h - layout->tile_border_y, ymax); } + +/** + * If \a path leads to a .blend, remove the trailing slash (if needed). + */ +void file_path_to_ui_path(const char *path, char *r_path, int max_size) +{ + char tmp_path[PATH_MAX]; + BLI_strncpy(tmp_path, path, sizeof(tmp_path)); + BLI_path_slash_rstrip(tmp_path); + BLI_strncpy(r_path, BLO_has_bfile_extension(tmp_path) ? tmp_path : path, max_size); +} diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 9e51b6ca4ba..d66219c7549 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -53,13 +53,18 @@ # include "BLI_winstuff.h" #endif +#include "BKE_asset.h" #include "BKE_context.h" #include "BKE_global.h" #include "BKE_icons.h" #include "BKE_idtype.h" +#include "BKE_lib_id.h" #include "BKE_main.h" +#include "BKE_main_idmap.h" +#include "BKE_preferences.h" #include "BLO_readfile.h" +#include "DNA_asset_types.h" #include "DNA_space_types.h" #include "ED_datafiles.h" @@ -82,6 +87,8 @@ #include "filelist.h" +#define FILEDIR_NBR_ENTRIES_UNSET -1 + /* ----------------- FOLDERLIST (previous/next) -------------- */ typedef struct FolderList { @@ -89,12 +96,6 @@ typedef struct FolderList { char *foldername; } FolderList; -ListBase *folderlist_new(void) -{ - ListBase *p = MEM_callocN(sizeof(*p), __func__); - return p; -} - void folderlist_popdir(struct ListBase *folderlist, char *dir) { const char *prev_dir; @@ -117,6 +118,10 @@ void folderlist_popdir(struct ListBase *folderlist, char *dir) void folderlist_pushdir(ListBase *folderlist, const char *dir) { + if (!dir[0]) { + return; + } + struct FolderList *folder, *previous_folder; previous_folder = folderlist->last; @@ -149,17 +154,18 @@ const char *folderlist_peeklastdir(ListBase *folderlist) int folderlist_clear_next(struct SpaceFile *sfile) { + const FileSelectParams *params = ED_fileselect_get_active_params(sfile); struct FolderList *folder; /* if there is no folder_next there is nothing we can clear */ - if (!sfile->folders_next) { + if (BLI_listbase_is_empty(sfile->folders_next)) { return 0; } /* if previous_folder, next_folder or refresh_folder operators are executed * it doesn't clear folder_next */ folder = sfile->folders_prev->last; - if ((!folder) || (BLI_path_cmp(folder->foldername, sfile->params->dir) == 0)) { + if ((!folder) || (BLI_path_cmp(folder->foldername, params->dir) == 0)) { return 0; } @@ -179,23 +185,79 @@ void folderlist_free(ListBase *folderlist) } } -ListBase *folderlist_duplicate(ListBase *folderlist) +static ListBase folderlist_duplicate(ListBase *folderlist) { + ListBase folderlistn = {NULL}; - if (folderlist) { - ListBase *folderlistn = MEM_callocN(sizeof(*folderlistn), __func__); - FolderList *folder; + BLI_duplicatelist(&folderlistn, folderlist); + + for (FolderList *folder = folderlistn.first; folder; folder = folder->next) { + folder->foldername = MEM_dupallocN(folder->foldername); + } + return folderlistn; +} - BLI_duplicatelist(folderlistn, folderlist); +/* ----------------- Folder-History (wraps/owns file list above) -------------- */ - for (folder = folderlistn->first; folder; folder = folder->next) { - folder->foldername = MEM_dupallocN(folder->foldername); +static FileFolderHistory *folder_history_find(const SpaceFile *sfile, eFileBrowse_Mode browse_mode) +{ + LISTBASE_FOREACH (FileFolderHistory *, history, &sfile->folder_histories) { + if (history->browse_mode == browse_mode) { + return history; } - return folderlistn; } + return NULL; } +void folder_history_list_ensure_for_active_browse_mode(SpaceFile *sfile) +{ + FileFolderHistory *history = folder_history_find(sfile, sfile->browse_mode); + + if (!history) { + history = MEM_callocN(sizeof(*history), __func__); + history->browse_mode = sfile->browse_mode; + BLI_addtail(&sfile->folder_histories, history); + } + + sfile->folders_next = &history->folders_next; + sfile->folders_prev = &history->folders_prev; +} + +static void folder_history_entry_free(SpaceFile *sfile, FileFolderHistory *history) +{ + if (sfile->folders_prev == &history->folders_prev) { + sfile->folders_prev = NULL; + } + if (sfile->folders_next == &history->folders_next) { + sfile->folders_next = NULL; + } + folderlist_free(&history->folders_prev); + folderlist_free(&history->folders_next); + BLI_freelinkN(&sfile->folder_histories, history); +} + +void folder_history_list_free(SpaceFile *sfile) +{ + LISTBASE_FOREACH_MUTABLE (FileFolderHistory *, history, &sfile->folder_histories) { + folder_history_entry_free(sfile, history); + } +} + +ListBase folder_history_list_duplicate(ListBase *listbase) +{ + ListBase histories = {NULL}; + + LISTBASE_FOREACH (FileFolderHistory *, history, listbase) { + FileFolderHistory *history_new = MEM_dupallocN(history); + history_new->folders_prev = folderlist_duplicate(&history->folders_prev); + history_new->folders_next = folderlist_duplicate(&history->folders_next); + BLI_addtail(&histories, history_new); + } + + return histories; +} + /* ------------------FILELIST------------------------ */ typedef struct FileListInternEntry { @@ -215,6 +277,24 @@ typedef struct FileListInternEntry { /** not strictly needed, but used during sorting, avoids to have to recompute it there... */ char *name; + /** + * This is data from the current main, represented by this file. It's crucial that this is + * updated correctly on undo, redo and file reading (without UI). The space is responsible to + * take care of that. + */ + struct { + /** When showing local IDs (FILE_MAIN, FILE_MAIN_ASSET), the ID this file entry represents. */ + ID *id; + + /* For the few file types that have the preview already in memory. For others, there's delayed + * preview reading from disk. Non-owning pointer. */ + PreviewImage *preview_image; + } local_data; + + /** When the file represents an asset read from another file, it is stored here. + * Owning pointer. */ + AssetMetaData *imported_asset_data; + /** Defined in BLI_fileops.h */ eFileAttributes attributes; BLI_stat_t st; @@ -266,7 +346,11 @@ typedef struct FileListEntryPreview { char path[FILE_MAX]; uint flags; int index; - ImBuf *img; + /* Some file types load the memory from runtime data, not from disk. We just wait until it's done + * generating (BKE_previewimg_is_finished()). */ + PreviewImage *in_memory_preview; + + int icon_id; } FileListEntryPreview; /* Dummy wrapper around FileListEntryPreview to ensure we do not access freed memory when freeing @@ -289,11 +373,16 @@ enum { FLF_HIDE_DOT = 1 << 1, FLF_HIDE_PARENT = 1 << 2, FLF_HIDE_LIB_DIR = 1 << 3, + FLF_ASSETS_ONLY = 1 << 4, }; typedef struct FileList { FileDirEntryArr filelist; + eFileSelectType type; + /* The library this list was created for. Stored here so we know when to re-read. */ + FileSelectAssetLibraryUID *asset_library; + short flags; short sort; @@ -323,10 +412,13 @@ typedef struct FileList { bool (*checkdirf)(struct FileList *, char *, const bool); /* Fill filelist (to be called by read job). */ - void (*read_jobf)(struct FileList *, const char *, short *, short *, float *, ThreadMutex *); + void (*read_jobf)( + Main *, struct FileList *, const char *, short *, short *, float *, ThreadMutex *); /* Filter an entry of current filelist. */ bool (*filterf)(struct FileListInternEntry *, const char *, FileListFilter *); + + short tags; /* FileListTags */ } FileList; /* FileList.flags */ @@ -339,6 +431,14 @@ enum { FL_SORT_INVERT = 1 << 5, }; +/* FileList.tags */ +enum FileListTags { + /** The file list has references to main data (IDs) and needs special care. */ + FILELIST_TAGS_USES_MAIN_DATA = (1 << 0), + /** The file list type is not thread-safe. */ + FILELIST_TAGS_NO_THREADS = (1 << 2), +}; + #define SPECIAL_IMG_SIZE 256 #define SPECIAL_IMG_ROWS 1 #define SPECIAL_IMG_COLS 7 @@ -356,24 +456,34 @@ enum { static ImBuf *gSpecialFileImages[SPECIAL_IMG_MAX]; -static void filelist_readjob_main(FileList *filelist, +static void filelist_readjob_main(Main *current_main, + FileList *filelist, const char *main_name, short *stop, short *do_update, float *progress, ThreadMutex *lock); -static void filelist_readjob_lib(FileList *filelist, +static void filelist_readjob_lib(Main *current_main, + FileList *filelist, const char *main_name, short *stop, short *do_update, float *progress, ThreadMutex *lock); -static void filelist_readjob_dir(FileList *filelist, +static void filelist_readjob_dir(Main *current_main, + FileList *filelist, const char *main_name, short *stop, short *do_update, float *progress, ThreadMutex *lock); +static void filelist_readjob_main_assets(Main *current_main, + FileList *filelist, + const char *main_name, + short *stop, + short *do_update, + float *progress, + ThreadMutex *lock); /* helper, could probably go in BKE actually? */ static int groupname_to_code(const char *group); @@ -629,7 +739,7 @@ void filelist_setsorting(struct FileList *filelist, const short sort, bool inver /* ********** Filter helpers ********** */ /* True if filename is meant to be hidden, eg. starting with period. */ -static bool is_hidden_dot_filename(const char *filename, FileListInternEntry *file) +static bool is_hidden_dot_filename(const char *filename, const FileListInternEntry *file) { if (filename[0] == '.' && !ELEM(filename[1], '.', '\0')) { return true; /* ignore .file */ @@ -670,8 +780,8 @@ static bool is_hidden_dot_filename(const char *filename, FileListInternEntry *fi /* True if should be hidden, based on current filtering. */ static bool is_filtered_hidden(const char *filename, - FileListFilter *filter, - FileListInternEntry *file) + const FileListFilter *filter, + const FileListInternEntry *file) { if ((filename[0] == '.') && (filename[1] == '\0')) { return true; /* Ignore . */ @@ -693,6 +803,11 @@ static bool is_filtered_hidden(const char *filename, return true; } #endif + /* For data-blocks (but not the group directories), check the asset-only filter. */ + if (!(file->typeflag & FILE_TYPE_DIR) && (file->typeflag & FILE_TYPE_BLENDERLIB) && + (filter->flags & FLF_ASSETS_ONLY) && !(file->typeflag & FILE_TYPE_ASSET)) { + return true; + } return false; } @@ -736,51 +851,61 @@ static bool is_filtered_file(FileListInternEntry *file, return is_filtered; } -static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileListFilter *filter) +static bool is_filtered_id_file(const FileListInternEntry *file, + const char *id_group, + const char *name, + const FileListFilter *filter) { - bool is_filtered; - char path[FILE_MAX_LIBEXTRA], dir[FILE_MAX_LIBEXTRA], *group, *name; - - BLI_join_dirfile(path, sizeof(path), root, file->relpath); - - if (BLO_library_path_explode(path, dir, &group, &name)) { - is_filtered = !is_filtered_hidden(file->relpath, filter, file); - if (is_filtered && !FILENAME_IS_CURRPAR(file->relpath)) { - /* We only check for types if some type are enabled in filtering. */ - if ((filter->filter || filter->filter_id) && (filter->flags & FLF_DO_FILTER)) { - if (file->typeflag & FILE_TYPE_DIR) { - if (file->typeflag & - (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { - if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) { - is_filtered = false; - } - } - else { - if (!(filter->filter & FILE_TYPE_FOLDER)) { - is_filtered = false; - } + bool is_filtered = !is_filtered_hidden(file->relpath, filter, file); + if (is_filtered && !FILENAME_IS_CURRPAR(file->relpath)) { + /* We only check for types if some type are enabled in filtering. */ + if ((filter->filter || filter->filter_id) && (filter->flags & FLF_DO_FILTER)) { + if (file->typeflag & FILE_TYPE_DIR) { + if (file->typeflag & + (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { + if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) { + is_filtered = false; } } - if (is_filtered && group) { - if (!name && (filter->flags & FLF_HIDE_LIB_DIR)) { + else { + if (!(filter->filter & FILE_TYPE_FOLDER)) { is_filtered = false; } - else { - uint64_t filter_id = groupname_to_filter_id(group); - if (!(filter_id & filter->filter_id)) { - is_filtered = false; - } - } } } - /* If there's a filter string, apply it as filter even if FLF_DO_FILTER is not set. */ - if (is_filtered && (filter->filter_search[0] != '\0')) { - if (fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) != 0) { + if (is_filtered && id_group) { + if (!name && (filter->flags & FLF_HIDE_LIB_DIR)) { is_filtered = false; } + else { + uint64_t filter_id = groupname_to_filter_id(id_group); + if (!(filter_id & filter->filter_id)) { + is_filtered = false; + } + } + } + } + /* If there's a filter string, apply it as filter even if FLF_DO_FILTER is not set. */ + if (is_filtered && (filter->filter_search[0] != '\0')) { + if (fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) != 0) { + is_filtered = false; } } } + + return is_filtered; +} + +static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileListFilter *filter) +{ + bool is_filtered; + char path[FILE_MAX_LIBEXTRA], dir[FILE_MAX_LIBEXTRA], *group, *name; + + BLI_join_dirfile(path, sizeof(path), root, file->relpath); + + if (BLO_library_path_explode(path, dir, &group, &name)) { + is_filtered = is_filtered_id_file(file, group, name, filter); + } else { is_filtered = is_filtered_file(file, root, filter); } @@ -795,6 +920,14 @@ static bool is_filtered_main(FileListInternEntry *file, return !is_filtered_hidden(file->relpath, filter, file); } +static bool is_filtered_main_assets(FileListInternEntry *file, + const char *UNUSED(dir), + FileListFilter *filter) +{ + /* "Filtered" means *not* being filtered out... So return true if the file should be visible. */ + return is_filtered_id_file(file, file->relpath, file->name, filter); +} + static void filelist_filter_clear(FileList *filelist) { filelist->flags |= FL_NEED_FILTERING; @@ -806,7 +939,7 @@ void filelist_filter(FileList *filelist) const int num_files = filelist->filelist.nbr_entries; FileListInternEntry **filtered_tmp, *file; - if (filelist->filelist.nbr_entries == 0) { + if (ELEM(filelist->filelist.nbr_entries, FILEDIR_NBR_ENTRIES_UNSET, 0)) { return; } @@ -857,6 +990,7 @@ void filelist_setfilter_options(FileList *filelist, const bool hide_parent, const uint64_t filter, const uint64_t filter_id, + const bool filter_assets_only, const char *filter_glob, const char *filter_search) { @@ -874,6 +1008,10 @@ void filelist_setfilter_options(FileList *filelist, filelist->filter_data.flags ^= FLF_HIDE_PARENT; update = true; } + if (((filelist->filter_data.flags & FLF_ASSETS_ONLY) != 0) != (filter_assets_only != 0)) { + filelist->filter_data.flags ^= FLF_ASSETS_ONLY; + update = true; + } if (filelist->filter_data.filter != filter) { filelist->filter_data.filter = filter; update = true; @@ -902,6 +1040,54 @@ void filelist_setfilter_options(FileList *filelist, } } +/** + * Checks two libraries for equality. + * \return True if the libraries match. + */ +static bool filelist_compare_asset_libraries(const FileSelectAssetLibraryUID *library_a, + const FileSelectAssetLibraryUID *library_b) +{ + if (library_a->type != library_b->type) { + return false; + } + if (library_a->type == FILE_ASSET_LIBRARY_CUSTOM) { + /* Don't only check the index, also check that it's valid. */ + bUserAssetLibrary *library_ptr_a = BKE_preferences_asset_library_find_from_index( + &U, library_a->custom_library_index); + return (library_ptr_a != NULL) && + (library_a->custom_library_index == library_b->custom_library_index); + } + + return true; +} + +/** + * \param asset_library: May be NULL to unset the library. + */ +void filelist_setlibrary(FileList *filelist, const FileSelectAssetLibraryUID *asset_library) +{ + /* Unset if needed. */ + if (!asset_library) { + if (filelist->asset_library) { + MEM_SAFE_FREE(filelist->asset_library); + filelist->flags |= FL_FORCE_RESET; + } + return; + } + + if (!filelist->asset_library) { + filelist->asset_library = MEM_mallocN(sizeof(*filelist->asset_library), + "filelist asset library"); + *filelist->asset_library = *asset_library; + + filelist->flags |= FL_FORCE_RESET; + } + else if (!filelist_compare_asset_libraries(filelist->asset_library, asset_library)) { + *filelist->asset_library = *asset_library; + filelist->flags |= FL_FORCE_RESET; + } +} + /* ********** Icon/image helpers ********** */ void filelist_init_icons(void) @@ -959,7 +1145,12 @@ ImBuf *filelist_getimage(struct FileList *filelist, const int index) { FileDirEntry *file = filelist_geticon_get_file(filelist, index); - return file->image; + return file->preview_icon_id ? BKE_icon_imbuf_get_buffer(file->preview_icon_id) : NULL; +} + +ImBuf *filelist_file_getimage(const FileDirEntry *file) +{ + return file->preview_icon_id ? BKE_icon_imbuf_get_buffer(file->preview_icon_id) : NULL; } static ImBuf *filelist_geticon_image_ex(FileDirEntry *file) @@ -987,12 +1178,12 @@ ImBuf *filelist_geticon_image(struct FileList *filelist, const int index) return filelist_geticon_image_ex(file); } -static int filelist_geticon_ex(FileDirEntry *file, +static int filelist_geticon_ex(const FileDirEntry *file, const char *root, const bool is_main, const bool ignore_libdir) { - const int typeflag = file->typeflag; + const eFileSel_File_Types typeflag = file->typeflag; if ((typeflag & FILE_TYPE_DIR) && !(ignore_libdir && (typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER)))) { @@ -1026,7 +1217,7 @@ static int filelist_geticon_ex(FileDirEntry *file, if (file->redirection_path) { target = file->redirection_path; } - else { + else if (root) { BLI_join_dirfile(fullpath, sizeof(fullpath), root, file->relpath); BLI_path_slash_ensure(fullpath); } @@ -1110,6 +1301,12 @@ int filelist_geticon(struct FileList *filelist, const int index, const bool is_m return filelist_geticon_ex(file, filelist->filelist.root, is_main, false); } +int ED_file_icon(const FileDirEntry *file) +{ + return file->preview_icon_id ? file->preview_icon_id : + filelist_geticon_ex(file, NULL, false, false); +} + /* ********** Main ********** */ static void parent_dir_until_exists_or_default_root(char *dir) @@ -1159,6 +1356,14 @@ static bool filelist_checkdir_main(struct FileList *filelist, char *r_dir, const return filelist_checkdir_lib(filelist, r_dir, do_change); } +static bool filelist_checkdir_main_assets(struct FileList *UNUSED(filelist), + char *UNUSED(r_dir), + const bool UNUSED(do_change)) +{ + /* Main is always valid. */ + return true; +} + static void filelist_entry_clear(FileDirEntry *entry) { if (entry->name) { @@ -1173,8 +1378,9 @@ static void filelist_entry_clear(FileDirEntry *entry) if (entry->redirection_path) { MEM_freeN(entry->redirection_path); } - if (entry->image) { - IMB_freeImBuf(entry->image); + if (entry->preview_icon_id) { + BKE_icon_delete(entry->preview_icon_id); + entry->preview_icon_id = 0; } /* For now, consider FileDirEntryRevision::poin as not owned here, * so no need to do anything about it */ @@ -1231,8 +1437,8 @@ static void filelist_direntryarr_free(FileDirEntryArr *array) #else BLI_assert(BLI_listbase_is_empty(&array->entries)); #endif - array->nbr_entries = 0; - array->nbr_entries_filtered = -1; + array->nbr_entries = FILEDIR_NBR_ENTRIES_UNSET; + array->nbr_entries_filtered = FILEDIR_NBR_ENTRIES_UNSET; array->entry_idx_start = -1; array->entry_idx_end = -1; } @@ -1248,6 +1454,10 @@ static void filelist_intern_entry_free(FileListInternEntry *entry) if (entry->name) { MEM_freeN(entry->name); } + /* If we own the asset-data (it was generated from external file data), free it. */ + if (entry->imported_asset_data) { + BKE_asset_metadata_free(&entry->imported_asset_data); + } MEM_freeN(entry); } @@ -1271,37 +1481,54 @@ static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdat FileListEntryPreview *preview = preview_taskdata->preview; ThumbSource source = 0; + bool done = false; // printf("%s: Start (%d)...\n", __func__, threadid); - // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img); - BLI_assert(preview->flags & - (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | FILE_TYPE_BLENDER | - FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)); - - if (preview->flags & FILE_TYPE_IMAGE) { - source = THB_SOURCE_IMAGE; - } - else if (preview->flags & - (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)) { - source = THB_SOURCE_BLEND; - } - else if (preview->flags & FILE_TYPE_MOVIE) { - source = THB_SOURCE_MOVIE; - } - else if (preview->flags & FILE_TYPE_FTFONT) { - source = THB_SOURCE_FONT; + if (preview->in_memory_preview) { + if (BKE_previewimg_is_finished(preview->in_memory_preview, ICON_SIZE_PREVIEW)) { + ImBuf *imbuf = BKE_previewimg_to_imbuf(preview->in_memory_preview, ICON_SIZE_PREVIEW); + preview->icon_id = BKE_icon_imbuf_create(imbuf); + done = true; + } } + else { + // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img); + BLI_assert(preview->flags & + (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | FILE_TYPE_BLENDER | + FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)); - IMB_thumb_path_lock(preview->path); - /* Always generate biggest preview size for now, it's simpler and avoids having to re-generate in - * case user switch to a bigger preview size. */ - preview->img = IMB_thumb_manage(preview->path, THB_LARGE, source); - IMB_thumb_path_unlock(preview->path); + if (preview->flags & FILE_TYPE_IMAGE) { + source = THB_SOURCE_IMAGE; + } + else if (preview->flags & + (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)) { + source = THB_SOURCE_BLEND; + } + else if (preview->flags & FILE_TYPE_MOVIE) { + source = THB_SOURCE_MOVIE; + } + else if (preview->flags & FILE_TYPE_FTFONT) { + source = THB_SOURCE_FONT; + } + + IMB_thumb_path_lock(preview->path); + /* Always generate biggest preview size for now, it's simpler and avoids having to re-generate + * in case user switch to a bigger preview size. */ + ImBuf *imbuf = IMB_thumb_manage(preview->path, THB_LARGE, source); + IMB_thumb_path_unlock(preview->path); + if (imbuf) { + preview->icon_id = BKE_icon_imbuf_create(imbuf); + } + + done = true; + } - /* That way task freeing function won't free th preview, since it does not own it anymore. */ - atomic_cas_ptr((void **)&preview_taskdata->preview, preview, NULL); - BLI_thread_queue_push(cache->previews_done, preview); + if (done) { + /* That way task freeing function won't free th preview, since it does not own it anymore. */ + atomic_cas_ptr((void **)&preview_taskdata->preview, preview, NULL); + BLI_thread_queue_push(cache->previews_done, preview); + } // printf("%s: End (%d)...\n", __func__, threadid); } @@ -1314,8 +1541,8 @@ static void filelist_cache_preview_freef(TaskPool *__restrict UNUSED(pool), void /* preview_taskdata->preview is atomically set to NULL once preview has been processed and sent * to previews_done queue. */ if (preview != NULL) { - if (preview->img) { - IMB_freeImBuf(preview->img); + if (preview->icon_id) { + BKE_icon_delete(preview->icon_id); } MEM_freeN(preview); } @@ -1341,8 +1568,8 @@ static void filelist_cache_previews_clear(FileListEntryCache *cache) while ((preview = BLI_thread_queue_pop_timeout(cache->previews_done, 0))) { // printf("%s: DONE %d - %s - %p\n", __func__, preview->index, preview->path, // preview->img); - if (preview->img) { - IMB_freeImBuf(preview->img); + if (preview->icon_id) { + BKE_icon_delete(preview->icon_id); } MEM_freeN(preview); } @@ -1373,10 +1600,11 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry BLI_assert(cache->flags & FLC_PREVIEWS_ACTIVE); - if (!entry->image && !(entry->flags & FILE_ENTRY_INVALID_PREVIEW) && + if (!entry->preview_icon_id && !(entry->flags & FILE_ENTRY_INVALID_PREVIEW) && (entry->typeflag & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB))) { FileListEntryPreview *preview = MEM_mallocN(sizeof(*preview), __func__); + FileListInternEntry *intern_entry = filelist->filelist_intern.filtered[index]; if (entry->redirection_path) { BLI_strncpy(preview->path, entry->redirection_path, FILE_MAXDIR); @@ -1388,7 +1616,8 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry preview->index = index; preview->flags = entry->typeflag; - preview->img = NULL; + preview->in_memory_preview = intern_entry->local_data.preview_image; + preview->icon_id = 0; // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img); filelist_cache_preview_ensure_running(cache); @@ -1496,25 +1725,45 @@ FileList *filelist_new(short type) p->selection_state = BLI_ghash_new( BLI_ghashutil_uinthash_v4_p, BLI_ghashutil_uinthash_v4_cmp, __func__); + p->filelist.nbr_entries = FILEDIR_NBR_ENTRIES_UNSET; + filelist_settype(p, type); - switch (type) { + return p; +} + +void filelist_settype(FileList *filelist, short type) +{ + if (filelist->type == type) { + return; + } + + filelist->type = type; + filelist->tags = 0; + switch (filelist->type) { case FILE_MAIN: - p->checkdirf = filelist_checkdir_main; - p->read_jobf = filelist_readjob_main; - p->filterf = is_filtered_main; + filelist->checkdirf = filelist_checkdir_main; + filelist->read_jobf = filelist_readjob_main; + filelist->filterf = is_filtered_main; break; case FILE_LOADLIB: - p->checkdirf = filelist_checkdir_lib; - p->read_jobf = filelist_readjob_lib; - p->filterf = is_filtered_lib; + filelist->checkdirf = filelist_checkdir_lib; + filelist->read_jobf = filelist_readjob_lib; + filelist->filterf = is_filtered_lib; + break; + case FILE_MAIN_ASSET: + filelist->checkdirf = filelist_checkdir_main_assets; + filelist->read_jobf = filelist_readjob_main_assets; + filelist->filterf = is_filtered_main_assets; + filelist->tags |= FILELIST_TAGS_USES_MAIN_DATA | FILELIST_TAGS_NO_THREADS; break; default: - p->checkdirf = filelist_checkdir_dir; - p->read_jobf = filelist_readjob_dir; - p->filterf = is_filtered_file; + filelist->checkdirf = filelist_checkdir_dir; + filelist->read_jobf = filelist_readjob_dir; + filelist->filterf = is_filtered_file; break; } - return p; + + filelist->flags |= FL_FORCE_RESET; } void filelist_clear_ex(struct FileList *filelist, const bool do_cache, const bool do_selection) @@ -1559,6 +1808,8 @@ void filelist_free(struct FileList *filelist) filelist->selection_state = NULL; } + MEM_SAFE_FREE(filelist->asset_library); + memset(&filelist->filter_data, 0, sizeof(filelist->filter_data)); filelist->flags &= ~(FL_NEED_SORTING | FL_NEED_FILTERING); @@ -1579,7 +1830,7 @@ BlendHandle *filelist_lib(struct FileList *filelist) static const char *fileentry_uiname(const char *root, const char *relpath, - const int typeflag, + const eFileSel_File_Types typeflag, char *buff) { char *name = NULL; @@ -1623,11 +1874,12 @@ bool filelist_is_dir(struct FileList *filelist, const char *path) */ void filelist_setdir(struct FileList *filelist, char *r_dir) { + const bool allow_invalid = filelist->asset_library != NULL; BLI_assert(strlen(r_dir) < FILE_MAX_LIBEXTRA); BLI_path_normalize_dir(BKE_main_blendfile_path_from_global(), r_dir); - const bool is_valid_path = filelist->checkdirf(filelist, r_dir, true); - BLI_assert(is_valid_path); + const bool is_valid_path = filelist->checkdirf(filelist, r_dir, !allow_invalid); + BLI_assert(is_valid_path || allow_invalid); UNUSED_VARS_NDEBUG(is_valid_path); if (!STREQ(filelist->filelist.root, r_dir)) { @@ -1644,11 +1896,16 @@ void filelist_setrecursion(struct FileList *filelist, const int recursion_level) } } -bool filelist_force_reset(struct FileList *filelist) +bool filelist_needs_force_reset(FileList *filelist) { return (filelist->flags & FL_FORCE_RESET) != 0; } +void filelist_tag_force_reset(FileList *filelist) +{ + filelist->flags |= FL_FORCE_RESET; +} + bool filelist_is_ready(struct FileList *filelist) { return (filelist->flags & FL_IS_READY) != 0; @@ -1659,6 +1916,11 @@ bool filelist_pending(struct FileList *filelist) return (filelist->flags & FL_IS_PENDING) != 0; } +bool filelist_needs_reset_on_main_changes(const FileList *filelist) +{ + return (filelist->tags & FILELIST_TAGS_USES_MAIN_DATA) != 0; +} + /** * Limited version of full update done by space_file's file_refresh(), * to be used by operators and such. @@ -1667,7 +1929,7 @@ bool filelist_pending(struct FileList *filelist) */ int filelist_files_ensure(FileList *filelist) { - if (!filelist_force_reset(filelist) || !filelist_empty(filelist)) { + if (!filelist_needs_force_reset(filelist) || !filelist_needs_reading(filelist)) { filelist_sort(filelist); filelist_filter(filelist); } @@ -1700,6 +1962,17 @@ static FileDirEntry *filelist_file_create_entry(FileList *filelist, const int in if (entry->redirection_path) { ret->redirection_path = BLI_strdup(entry->redirection_path); } + ret->id = entry->local_data.id; + ret->asset_data = entry->imported_asset_data ? entry->imported_asset_data : NULL; + if (ret->id && (ret->asset_data == NULL)) { + ret->asset_data = ret->id->asset_data; + } + /* For some file types the preview is already available. */ + if (entry->local_data.preview_image && + BKE_previewimg_is_finished(entry->local_data.preview_image, ICON_SIZE_PREVIEW)) { + ImBuf *ibuf = BKE_previewimg_to_imbuf(entry->local_data.preview_image, ICON_SIZE_PREVIEW); + ret->preview_icon_id = BKE_icon_imbuf_create(ibuf); + } BLI_addtail(&cache->cached_entries, ret); return ret; } @@ -1769,7 +2042,7 @@ int filelist_file_findpath(struct FileList *filelist, const char *filename) { int fidx = -1; - if (filelist->filelist.nbr_entries_filtered < 0) { + if (filelist->filelist.nbr_entries_filtered == FILEDIR_NBR_ENTRIES_UNSET) { return fidx; } @@ -1787,9 +2060,17 @@ int filelist_file_findpath(struct FileList *filelist, const char *filename) return -1; } +/** + * Get the ID a file represents (if any). For #FILE_MAIN, #FILE_MAIN_ASSET. + */ +ID *filelist_file_get_id(const FileDirEntry *file) +{ + return file->id; +} + FileDirEntry *filelist_entry_find_uuid(struct FileList *filelist, const int uuid[4]) { - if (filelist->filelist.nbr_entries_filtered < 0) { + if (filelist->filelist.nbr_entries_filtered == FILEDIR_NBR_ENTRIES_UNSET) { return NULL; } @@ -2146,15 +2427,17 @@ bool filelist_cache_previews_update(FileList *filelist) // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img); - if (preview->img) { + if (preview->icon_id) { /* Due to asynchronous process, a preview for a given image may be generated several times, * i.e. entry->image may already be set at this point. */ - if (entry && !entry->image) { - entry->image = preview->img; + if (entry && !entry->preview_icon_id) { + /* Move ownership over icon. */ + entry->preview_icon_id = preview->icon_id; + preview->icon_id = 0; changed = true; } else { - IMB_freeImBuf(preview->img); + BKE_icon_delete(preview->icon_id); } } else if (entry) { @@ -2312,9 +2595,9 @@ int ED_file_extension_icon(const char *path) } } -int filelist_empty(struct FileList *filelist) +int filelist_needs_reading(struct FileList *filelist) { - return (filelist->filelist.nbr_entries == 0); + return (filelist->filelist.nbr_entries == FILEDIR_NBR_ENTRIES_UNSET); } uint filelist_entry_select_set(const FileList *filelist, @@ -2563,8 +2846,8 @@ static int filelist_readjob_list_dir(const char *root, static int filelist_readjob_list_lib(const char *root, ListBase *entries, const bool skip_currpar) { FileListInternEntry *entry; - LinkNode *ln, *names; - int i, nnames, idcode = 0, nbr_entries = 0; + LinkNode *ln, *names = NULL, *datablock_infos = NULL; + int i, nitems, idcode = 0, nbr_entries = 0; char dir[FILE_MAX_LIBEXTRA], *group; bool ok; @@ -2586,11 +2869,11 @@ static int filelist_readjob_list_lib(const char *root, ListBase *entries, const * and freed in filelist_entry_free. */ if (group) { idcode = groupname_to_code(group); - names = BLO_blendhandle_get_datablock_names(libfiledata, idcode, &nnames); + datablock_infos = BLO_blendhandle_get_datablock_info(libfiledata, idcode, &nitems); } else { names = BLO_blendhandle_get_linkable_groups(libfiledata); - nnames = BLI_linklist_count(names); + nitems = BLI_linklist_count(names); } BLO_blendhandle_close(libfiledata); @@ -2603,12 +2886,18 @@ static int filelist_readjob_list_lib(const char *root, ListBase *entries, const nbr_entries++; } - for (i = 0, ln = names; i < nnames; i++, ln = ln->next) { - const char *blockname = ln->link; + for (i = 0, ln = (datablock_infos ? datablock_infos : names); i < nitems; i++, ln = ln->next) { + struct BLODataBlockInfo *info = datablock_infos ? ln->link : NULL; + const char *blockname = info ? info->name : ln->link; entry = MEM_callocN(sizeof(*entry), __func__); entry->relpath = BLI_strdup(blockname); entry->typeflag |= FILE_TYPE_BLENDERLIB; + if (info && info->asset_data) { + entry->typeflag |= FILE_TYPE_ASSET; + /* Moves ownership! */ + entry->imported_asset_data = info->asset_data; + } if (!(group && idcode)) { entry->typeflag |= FILE_TYPE_DIR; entry->blentype = groupname_to_code(blockname); @@ -2620,7 +2909,7 @@ static int filelist_readjob_list_lib(const char *root, ListBase *entries, const nbr_entries++; } - BLI_linklist_free(names, free); + BLI_linklist_freeN(datablock_infos ? datablock_infos : names); return nbr_entries; } @@ -2819,7 +3108,10 @@ static void filelist_readjob_do(const bool do_lib, // BLI_assert(filelist->filtered == NULL); BLI_assert(BLI_listbase_is_empty(&filelist->filelist.entries) && - (filelist->filelist.nbr_entries == 0)); + (filelist->filelist.nbr_entries == FILEDIR_NBR_ENTRIES_UNSET)); + + /* A valid, but empty directory from now. */ + filelist->filelist.nbr_entries = 0; todo_dirs = BLI_stack_new(sizeof(*td_dir), __func__); td_dir = BLI_stack_push_r(todo_dirs); @@ -2931,7 +3223,8 @@ static void filelist_readjob_do(const bool do_lib, BLI_stack_free(todo_dirs); } -static void filelist_readjob_dir(FileList *filelist, +static void filelist_readjob_dir(Main *UNUSED(current_main), + FileList *filelist, const char *main_name, short *stop, short *do_update, @@ -2941,7 +3234,8 @@ static void filelist_readjob_dir(FileList *filelist, filelist_readjob_do(false, filelist, main_name, stop, do_update, progress, lock); } -static void filelist_readjob_lib(FileList *filelist, +static void filelist_readjob_lib(Main *UNUSED(current_main), + FileList *filelist, const char *main_name, short *stop, short *do_update, @@ -2951,7 +3245,8 @@ static void filelist_readjob_lib(FileList *filelist, filelist_readjob_do(true, filelist, main_name, stop, do_update, progress, lock); } -static void filelist_readjob_main(FileList *filelist, +static void filelist_readjob_main(Main *current_main, + FileList *filelist, const char *main_name, short *stop, short *do_update, @@ -2959,12 +3254,67 @@ static void filelist_readjob_main(FileList *filelist, ThreadMutex *lock) { /* TODO! */ - filelist_readjob_dir(filelist, main_name, stop, do_update, progress, lock); + filelist_readjob_dir(current_main, filelist, main_name, stop, do_update, progress, lock); +} + +/** + * \warning Acts on main, so NOT thread-safe! + */ +static void filelist_readjob_main_assets(Main *current_main, + FileList *filelist, + const char *UNUSED(main_name), + short *UNUSED(stop), + short *do_update, + float *UNUSED(progress), + ThreadMutex *UNUSED(lock)) +{ + BLI_assert(BLI_listbase_is_empty(&filelist->filelist.entries) && + (filelist->filelist.nbr_entries == FILEDIR_NBR_ENTRIES_UNSET)); + + /* A valid, but empty directory from now. */ + filelist->filelist.nbr_entries = 0; + + FileListInternEntry *entry; + ListBase tmp_entries = {0}; + ID *id_iter; + int nbr_entries = 0; + + FOREACH_MAIN_ID_BEGIN (current_main, id_iter) { + if (!id_iter->asset_data) { + continue; + } + + const char *id_code_name = BKE_idtype_idcode_to_name(GS(id_iter->name)); + + entry = MEM_callocN(sizeof(*entry), __func__); + entry->relpath = BLI_strdup(id_code_name); + entry->name = BLI_strdup(id_iter->name + 2); + entry->typeflag |= FILE_TYPE_BLENDERLIB | FILE_TYPE_ASSET; + entry->blentype = GS(id_iter->name); + *((uint32_t *)entry->uuid) = atomic_add_and_fetch_uint32( + (uint32_t *)filelist->filelist_intern.curr_uuid, 1); + entry->local_data.preview_image = BKE_asset_metadata_preview_get_from_id(id_iter->asset_data, + id_iter); + entry->local_data.id = id_iter; + nbr_entries++; + BLI_addtail(&tmp_entries, entry); + } + FOREACH_MAIN_ID_END; + + if (nbr_entries) { + *do_update = true; + + BLI_movelisttolist(&filelist->filelist.entries, &tmp_entries); + filelist->filelist.nbr_entries += nbr_entries; + filelist->filelist.nbr_entries_filtered = filelist->filelist.entry_idx_start = + filelist->filelist.entry_idx_end = -1; + } } typedef struct FileListReadJob { ThreadMutex lock; char main_name[FILE_MAX]; + Main *current_main; struct FileList *filelist; /** XXX We may use a simpler struct here... just a linked list and root path? */ struct FileList *tmp_filelist; @@ -2984,7 +3334,7 @@ static void filelist_readjob_startjob(void *flrjv, short *stop, short *do_update flrj->tmp_filelist = MEM_dupallocN(flrj->filelist); BLI_listbase_clear(&flrj->tmp_filelist->filelist.entries); - flrj->tmp_filelist->filelist.nbr_entries = 0; + flrj->tmp_filelist->filelist.nbr_entries = FILEDIR_NBR_ENTRIES_UNSET; flrj->tmp_filelist->filelist_intern.filtered = NULL; BLI_listbase_clear(&flrj->tmp_filelist->filelist_intern.entries); @@ -2995,11 +3345,17 @@ static void filelist_readjob_startjob(void *flrjv, short *stop, short *do_update flrj->tmp_filelist->libfiledata = NULL; memset(&flrj->tmp_filelist->filelist_cache, 0, sizeof(flrj->tmp_filelist->filelist_cache)); flrj->tmp_filelist->selection_state = NULL; + flrj->tmp_filelist->asset_library = NULL; BLI_mutex_unlock(&flrj->lock); - flrj->tmp_filelist->read_jobf( - flrj->tmp_filelist, flrj->main_name, stop, do_update, progress, &flrj->lock); + flrj->tmp_filelist->read_jobf(flrj->current_main, + flrj->tmp_filelist, + flrj->main_name, + stop, + do_update, + progress, + &flrj->lock); } static void filelist_readjob_update(void *flrjv) @@ -3014,7 +3370,7 @@ static void filelist_readjob_update(void *flrjv) BLI_mutex_lock(&flrj->lock); - if (flrj->tmp_filelist->filelist.nbr_entries) { + if (flrj->tmp_filelist->filelist.nbr_entries > 0) { /* We just move everything out of 'thread context' into final list. */ new_nbr_entries = flrj->tmp_filelist->filelist.nbr_entries; BLI_movelisttolist(&new_entries, &flrj->tmp_filelist->filelist.entries); @@ -3032,7 +3388,7 @@ static void filelist_readjob_update(void *flrjv) /* if no new_nbr_entries, this is NOP */ BLI_movelisttolist(&fl_intern->entries, &new_entries); - flrj->filelist->filelist.nbr_entries = nbr_entries + new_nbr_entries; + flrj->filelist->filelist.nbr_entries = MAX2(nbr_entries, 0) + new_nbr_entries; } static void filelist_readjob_endjob(void *flrjv) @@ -3073,16 +3429,36 @@ void filelist_readjob_start(FileList *filelist, const bContext *C) wmJob *wm_job; FileListReadJob *flrj; + if (!filelist_is_dir(filelist, filelist->filelist.root)) { + return; + } + /* prepare job data */ flrj = MEM_callocN(sizeof(*flrj), __func__); flrj->filelist = filelist; + flrj->current_main = bmain; BLI_strncpy(flrj->main_name, BKE_main_blendfile_path(bmain), sizeof(flrj->main_name)); filelist->flags &= ~(FL_FORCE_RESET | FL_IS_READY); filelist->flags |= FL_IS_PENDING; + /* Init even for single threaded execution. Called functions use it. */ BLI_mutex_init(&flrj->lock); + if (filelist->tags & FILELIST_TAGS_NO_THREADS) { + short dummy_stop = false; + short dummy_do_update = false; + float dummy_progress = 0.0f; + + /* Single threaded execution. Just directly call the callbacks. */ + filelist_readjob_startjob(flrj, &dummy_stop, &dummy_do_update, &dummy_progress); + filelist_readjob_endjob(flrj); + filelist_readjob_free(flrj); + + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); + return; + } + /* setup job */ wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h index 4b8cc052382..16984bb6e43 100644 --- a/source/blender/editors/space_file/filelist.h +++ b/source/blender/editors/space_file/filelist.h @@ -29,6 +29,7 @@ extern "C" { struct BlendHandle; struct FileList; +struct FileSelectAssetLibraryUID; struct FileSelection; struct wmWindowManager; @@ -46,14 +47,16 @@ typedef enum FileCheckType { CHECK_ALL = 3, } FileCheckType; -struct ListBase *folderlist_new(void); void folderlist_free(struct ListBase *folderlist); -struct ListBase *folderlist_duplicate(ListBase *folderlist); void folderlist_popdir(struct ListBase *folderlist, char *dir); void folderlist_pushdir(struct ListBase *folderlist, const char *dir); const char *folderlist_peeklastdir(struct ListBase *folderlist); int folderlist_clear_next(struct SpaceFile *sfile); +void folder_history_list_ensure_for_active_browse_mode(struct SpaceFile *sfile); +void folder_history_list_free(struct SpaceFile *sfile); +struct ListBase folder_history_list_duplicate(struct ListBase *listbase); + void filelist_setsorting(struct FileList *filelist, const short sort, bool invert_sort); void filelist_sort(struct FileList *filelist); @@ -63,17 +66,22 @@ void filelist_setfilter_options(struct FileList *filelist, const bool hide_parent, const uint64_t filter, const uint64_t filter_id, + const bool filter_assets_only, const char *filter_glob, const char *filter_search); void filelist_filter(struct FileList *filelist); +void filelist_setlibrary(struct FileList *filelist, + const struct FileSelectAssetLibraryUID *asset_library); void filelist_init_icons(void); void filelist_free_icons(void); struct ImBuf *filelist_getimage(struct FileList *filelist, const int index); +struct ImBuf *filelist_file_getimage(const FileDirEntry *file); struct ImBuf *filelist_geticon_image(struct FileList *filelist, const int index); int filelist_geticon(struct FileList *filelist, const int index, const bool is_main); struct FileList *filelist_new(short type); +void filelist_settype(struct FileList *filelist, short type); void filelist_clear(struct FileList *filelist); void filelist_clear_ex(struct FileList *filelist, const bool do_cache, const bool do_selection); void filelist_free(struct FileList *filelist); @@ -83,15 +91,18 @@ bool filelist_is_dir(struct FileList *filelist, const char *path); void filelist_setdir(struct FileList *filelist, char *r_dir); int filelist_files_ensure(struct FileList *filelist); -int filelist_empty(struct FileList *filelist); +int filelist_needs_reading(struct FileList *filelist); FileDirEntry *filelist_file(struct FileList *filelist, int index); int filelist_file_findpath(struct FileList *filelist, const char *file); +struct ID *filelist_file_get_id(const struct FileDirEntry *file); FileDirEntry *filelist_entry_find_uuid(struct FileList *filelist, const int uuid[4]); void filelist_file_cache_slidingwindow_set(struct FileList *filelist, size_t window_size); bool filelist_file_cache_block(struct FileList *filelist, const int index); -bool filelist_force_reset(struct FileList *filelist); +bool filelist_needs_force_reset(struct FileList *filelist); +void filelist_tag_force_reset(struct FileList *filelist); bool filelist_pending(struct FileList *filelist); +bool filelist_needs_reset_on_main_changes(const struct FileList *filelist); bool filelist_is_ready(struct FileList *filelist); unsigned int filelist_entry_select_set(const struct FileList *filelist, diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index 15c6972c5f5..b919a30e6cd 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -56,7 +56,9 @@ #include "BKE_appdir.h" #include "BKE_context.h" +#include "BKE_idtype.h" #include "BKE_main.h" +#include "BKE_preferences.h" #include "BLF_api.h" @@ -77,19 +79,76 @@ #define VERTLIST_MAJORCOLUMN_WIDTH (25 * UI_UNIT_X) -FileSelectParams *ED_fileselect_get_params(struct SpaceFile *sfile) +static void fileselect_initialize_params_common(SpaceFile *sfile, FileSelectParams *params) { - if (!sfile->params) { - ED_fileselect_set_params(sfile); + const char *blendfile_path = BKE_main_blendfile_path_from_global(); + + /* operator has no setting for this */ + params->active_file = -1; + + if (!params->dir[0]) { + if (blendfile_path[0] != '\0') { + BLI_split_dir_part(blendfile_path, params->dir, sizeof(params->dir)); + } + else { + const char *doc_path = BKE_appdir_folder_default(); + if (doc_path) { + BLI_strncpy(params->dir, doc_path, sizeof(params->dir)); + } + } + } + + folder_history_list_ensure_for_active_browse_mode(sfile); + folderlist_pushdir(sfile->folders_prev, params->dir); + + /* Switching thumbnails needs to recalc layout T28809. */ + if (sfile->layout) { + sfile->layout->dirty = true; } - return sfile->params; +} + +static void fileselect_ensure_updated_asset_params(SpaceFile *sfile) +{ + BLI_assert(sfile->browse_mode == FILE_BROWSE_MODE_ASSETS); + BLI_assert(sfile->op == NULL); + + FileAssetSelectParams *asset_params = sfile->asset_params; + + if (!asset_params) { + asset_params = sfile->asset_params = MEM_callocN(sizeof(*asset_params), + "FileAssetSelectParams"); + asset_params->base_params.details_flags = U_default.file_space_data.details_flags; + asset_params->asset_library.type = FILE_ASSET_LIBRARY_LOCAL; + asset_params->asset_library.custom_library_index = -1; + } + + FileSelectParams *base_params = &asset_params->base_params; + base_params->file[0] = '\0'; + base_params->filter_glob[0] = '\0'; + /* TODO this way of using filters to form categories is notably slower than specifying a + * "group" to read. That's because all types are read and filtering is applied afterwards. Would + * be nice if we could lazy-read individual groups. */ + base_params->flag |= U_default.file_space_data.flag | FILE_ASSETS_ONLY | FILE_FILTER; + base_params->flag &= ~FILE_DIRSEL_ONLY; + base_params->filter |= FILE_TYPE_BLENDERLIB; + base_params->filter_id = FILTER_ID_OB | FILTER_ID_GR; + base_params->display = FILE_IMGDISPLAY; + base_params->sort = FILE_SORT_ALPHA; + base_params->recursion_level = 1; + /* 'SMALL' size by default. More reasonable since this is typically used as regular editor, + * space is more of an issue here. */ + base_params->thumbnail_size = 96; + + fileselect_initialize_params_common(sfile, base_params); } /** * \note RNA_struct_property_is_set_ex is used here because we want * the previously used settings to be used here rather than overriding them */ -short ED_fileselect_set_params(SpaceFile *sfile) +static FileSelectParams *fileselect_ensure_updated_file_params(SpaceFile *sfile) { + BLI_assert(sfile->browse_mode == FILE_BROWSE_MODE_FILES); + FileSelectParams *params; wmOperator *op = sfile->op; @@ -136,20 +195,17 @@ short ED_fileselect_set_params(SpaceFile *sfile) RNA_string_get(op->ptr, "filepath", name); if (params->type == FILE_LOADLIB) { BLI_strncpy(params->dir, name, sizeof(params->dir)); - sfile->params->file[0] = '\0'; + params->file[0] = '\0'; } else { - BLI_split_dirfile(name, - sfile->params->dir, - sfile->params->file, - sizeof(sfile->params->dir), - sizeof(sfile->params->file)); + BLI_split_dirfile( + name, params->dir, params->file, sizeof(params->dir), sizeof(params->file)); } } else { if (is_directory && RNA_struct_property_is_set_ex(op->ptr, "directory", false)) { RNA_string_get(op->ptr, "directory", params->dir); - sfile->params->file[0] = '\0'; + params->file[0] = '\0'; } if (is_filename && RNA_struct_property_is_set_ex(op->ptr, "filename", false)) { @@ -298,34 +354,104 @@ short ED_fileselect_set_params(SpaceFile *sfile) params->filter_glob[0] = '\0'; } - /* operator has no setting for this */ - params->active_file = -1; + fileselect_initialize_params_common(sfile, params); - /* initialize the list with previous folders */ - if (!sfile->folders_prev) { - sfile->folders_prev = folderlist_new(); - } + return params; +} - if (!sfile->params->dir[0]) { - if (blendfile_path[0] != '\0') { - BLI_split_dir_part(blendfile_path, sfile->params->dir, sizeof(sfile->params->dir)); - } - else { - const char *doc_path = BKE_appdir_folder_default(); - if (doc_path) { - BLI_strncpy(sfile->params->dir, doc_path, sizeof(sfile->params->dir)); +/** + * If needed, create and return the file select parameters for the active browse mode. + */ +FileSelectParams *ED_fileselect_ensure_active_params(SpaceFile *sfile) +{ + switch ((eFileBrowse_Mode)sfile->browse_mode) { + case FILE_BROWSE_MODE_FILES: + if (!sfile->params) { + fileselect_ensure_updated_file_params(sfile); + } + return sfile->params; + case FILE_BROWSE_MODE_ASSETS: + if (!sfile->asset_params) { + fileselect_ensure_updated_asset_params(sfile); } + return &sfile->asset_params->base_params; + } + + BLI_assert(!"Invalid browse mode set in file space."); + return NULL; +} + +/** + * Get the file select parameters for the active browse mode. + */ +FileSelectParams *ED_fileselect_get_active_params(const SpaceFile *sfile) +{ + if (!sfile) { + /* Sometimes called in poll before space type was checked. */ + return NULL; + } + + switch ((eFileBrowse_Mode)sfile->browse_mode) { + case FILE_BROWSE_MODE_FILES: + return sfile->params; + case FILE_BROWSE_MODE_ASSETS: + return (FileSelectParams *)sfile->asset_params; + } + + BLI_assert(!"Invalid browse mode set in file space."); + return NULL; +} + +FileSelectParams *ED_fileselect_get_file_params(const SpaceFile *sfile) +{ + return (sfile->browse_mode == FILE_BROWSE_MODE_FILES) ? sfile->params : NULL; +} + +FileAssetSelectParams *ED_fileselect_get_asset_params(const SpaceFile *sfile) +{ + return (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS) ? sfile->asset_params : NULL; +} + +static void fileselect_refresh_asset_params(FileAssetSelectParams *asset_params) +{ + FileSelectAssetLibraryUID *library = &asset_params->asset_library; + FileSelectParams *base_params = &asset_params->base_params; + bUserAssetLibrary *user_library = NULL; + + /* Ensure valid repo, or fall-back to local one. */ + if (library->type == FILE_ASSET_LIBRARY_CUSTOM) { + BLI_assert(library->custom_library_index >= 0); + + user_library = BKE_preferences_asset_library_find_from_index(&U, + library->custom_library_index); + if (!user_library) { + library->type = FILE_ASSET_LIBRARY_LOCAL; } } - folderlist_pushdir(sfile->folders_prev, sfile->params->dir); + switch (library->type) { + case FILE_ASSET_LIBRARY_LOCAL: + base_params->dir[0] = '\0'; + break; + case FILE_ASSET_LIBRARY_CUSTOM: + BLI_assert(user_library); + BLI_strncpy(base_params->dir, user_library->path, sizeof(base_params->dir)); + break; + } + base_params->type = (library->type == FILE_ASSET_LIBRARY_LOCAL) ? FILE_MAIN_ASSET : FILE_LOADLIB; +} - /* Switching thumbnails needs to recalc layout T28809. */ - if (sfile->layout) { - sfile->layout->dirty = true; +void fileselect_refresh_params(SpaceFile *sfile) +{ + FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile); + if (asset_params) { + fileselect_refresh_asset_params(asset_params); } +} - return 1; +bool ED_fileselect_is_asset_browser(const SpaceFile *sfile) +{ + return (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS); } /* The subset of FileSelectParams.flag items we store into preferences. Note that FILE_SORT_ALPHA @@ -364,28 +490,28 @@ void ED_fileselect_set_params_from_userdef(SpaceFile *sfile) wmOperator *op = sfile->op; UserDef_FileSpaceData *sfile_udata = &U.file_space_data; - ED_fileselect_set_params(sfile); + sfile->browse_mode = FILE_BROWSE_MODE_FILES; + FileSelectParams *params = fileselect_ensure_updated_file_params(sfile); if (!op) { return; } - sfile->params->thumbnail_size = sfile_udata->thumbnail_size; - sfile->params->details_flags = sfile_udata->details_flags; - sfile->params->filter_id = sfile_udata->filter_id; + params->thumbnail_size = sfile_udata->thumbnail_size; + params->details_flags = sfile_udata->details_flags; + params->filter_id = sfile_udata->filter_id; /* Combine flags we take from params with the flags we take from userdef. */ - sfile->params->flag = (sfile->params->flag & ~PARAMS_FLAGS_REMEMBERED) | - (sfile_udata->flag & PARAMS_FLAGS_REMEMBERED); + params->flag = (params->flag & ~PARAMS_FLAGS_REMEMBERED) | + (sfile_udata->flag & PARAMS_FLAGS_REMEMBERED); if (file_select_use_default_display_type(sfile)) { - sfile->params->display = sfile_udata->display_type; + params->display = sfile_udata->display_type; } if (file_select_use_default_sort_type(sfile)) { - sfile->params->sort = sfile_udata->sort_type; + params->sort = sfile_udata->sort_type; /* For the default sorting, also take invert flag from userdef. */ - sfile->params->flag = (sfile->params->flag & ~FILE_SORT_INVERT) | - (sfile_udata->flag & FILE_SORT_INVERT); + params->flag = (params->flag & ~FILE_SORT_INVERT) | (sfile_udata->flag & FILE_SORT_INVERT); } } @@ -400,25 +526,26 @@ void ED_fileselect_params_to_userdef(SpaceFile *sfile, const int temp_win_size[2], const bool is_maximized) { + FileSelectParams *params = ED_fileselect_get_active_params(sfile); UserDef_FileSpaceData *sfile_udata_new = &U.file_space_data; UserDef_FileSpaceData sfile_udata_old = U.file_space_data; - sfile_udata_new->thumbnail_size = sfile->params->thumbnail_size; - sfile_udata_new->details_flags = sfile->params->details_flags; - sfile_udata_new->flag = sfile->params->flag & PARAMS_FLAGS_REMEMBERED; - sfile_udata_new->filter_id = sfile->params->filter_id; + sfile_udata_new->thumbnail_size = params->thumbnail_size; + sfile_udata_new->details_flags = params->details_flags; + sfile_udata_new->flag = params->flag & PARAMS_FLAGS_REMEMBERED; + sfile_udata_new->filter_id = params->filter_id; /* In some rare cases, operators ask for a specific display or sort type (e.g. chronological * sorting for "Recover Auto Save"). So the settings are optimized for a specific operation. * Don't let that change the userdef memory for more general cases. */ if (file_select_use_default_display_type(sfile)) { - sfile_udata_new->display_type = sfile->params->display; + sfile_udata_new->display_type = params->display; } if (file_select_use_default_sort_type(sfile)) { - sfile_udata_new->sort_type = sfile->params->sort; + sfile_udata_new->sort_type = params->sort; /* In this case also remember the invert flag. */ sfile_udata_new->flag = (sfile_udata_new->flag & ~FILE_SORT_INVERT) | - (sfile->params->flag & FILE_SORT_INVERT); + (params->flag & FILE_SORT_INVERT); } if (temp_win_size && !is_maximized) { @@ -432,14 +559,6 @@ void ED_fileselect_params_to_userdef(SpaceFile *sfile, } } -void ED_fileselect_reset_params(SpaceFile *sfile) -{ - sfile->params->type = FILE_UNIX; - sfile->params->flag = 0; - sfile->params->title[0] = '\0'; - sfile->params->active_file = -1; -} - /** * Sets FileSelectParams->file (name of selected file) */ @@ -447,7 +566,8 @@ void fileselect_file_set(SpaceFile *sfile, const int index) { const struct FileDirEntry *file = filelist_file(sfile->files, index); if (file && file->relpath && file->relpath[0] && !(file->typeflag & FILE_TYPE_DIR)) { - BLI_strncpy(sfile->params->file, file->relpath, FILE_MAXFILE); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); + BLI_strncpy(params->file, file->relpath, FILE_MAXFILE); } } @@ -759,7 +879,7 @@ static void file_attribute_columns_init(const FileSelectParams *params, FileLayo void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *region) { - FileSelectParams *params = ED_fileselect_get_params(sfile); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); FileLayout *layout = NULL; View2D *v2d = ®ion->v2d; int numfiles; @@ -873,7 +993,8 @@ void ED_file_change_dir_ex(bContext *C, bScreen *screen, ScrArea *area) return; } SpaceFile *sfile = area->spacedata.first; - if (sfile->params) { + FileSelectParams *params = ED_fileselect_get_active_params(sfile); + if (params) { wmWindowManager *wm = CTX_wm_manager(C); Scene *scene = WM_windows_scene_get_from_screen(wm, screen); if (LIKELY(scene != NULL)) { @@ -882,20 +1003,20 @@ void ED_file_change_dir_ex(bContext *C, bScreen *screen, ScrArea *area) /* Clear search string, it is very rare to want to keep that filter while changing dir, * and usually very annoying to keep it actually! */ - sfile->params->filter_search[0] = '\0'; - sfile->params->active_file = -1; + params->filter_search[0] = '\0'; + params->active_file = -1; - if (!filelist_is_dir(sfile->files, sfile->params->dir)) { - BLI_strncpy(sfile->params->dir, filelist_dir(sfile->files), sizeof(sfile->params->dir)); + if (!filelist_is_dir(sfile->files, params->dir)) { + BLI_strncpy(params->dir, filelist_dir(sfile->files), sizeof(params->dir)); /* could return but just refresh the current dir */ } - filelist_setdir(sfile->files, sfile->params->dir); + filelist_setdir(sfile->files, params->dir); if (folderlist_clear_next(sfile)) { folderlist_free(sfile->folders_next); } - folderlist_pushdir(sfile->folders_prev, sfile->params->dir); + folderlist_pushdir(sfile->folders_prev, params->dir); file_draw_check_ex(C, area); } @@ -1010,7 +1131,8 @@ void ED_fileselect_clear(wmWindowManager *wm, Scene *owner_scene, SpaceFile *sfi filelist_clear(sfile->files); } - sfile->params->highlight_file = -1; + FileSelectParams *params = ED_fileselect_get_active_params(sfile); + params->highlight_file = -1; WM_main_add_notifier(NC_SPACE | ND_SPACE_FILE_LIST, NULL); } @@ -1036,8 +1158,7 @@ void ED_fileselect_exit(wmWindowManager *wm, Scene *owner_scene, SpaceFile *sfil sfile->op = NULL; } - folderlist_free(sfile->folders_prev); - folderlist_free(sfile->folders_next); + folder_history_list_free(sfile); if (sfile->files) { ED_fileselect_clear(wm, owner_scene, sfile); diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 6ffe553e076..774dc54700c 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -35,6 +35,8 @@ #include "BKE_screen.h" #include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" #include "WM_api.h" #include "WM_message.h" @@ -55,6 +57,23 @@ #include "filelist.h" #include "fsmenu.h" +static ARegion *file_ui_region_ensure(ScrArea *area, ARegion *region_prev) +{ + ARegion *region; + + if ((region = BKE_area_find_region_type(area, RGN_TYPE_UI)) != NULL) { + return region; + } + + region = MEM_callocN(sizeof(ARegion), "execute region for file"); + BLI_insertlinkafter(&area->regionbase, region_prev, region); + region->regiontype = RGN_TYPE_UI; + region->alignment = RGN_ALIGN_TOP; + region->flag = RGN_FLAG_DYNAMIC_SIZE; + + return region; +} + static ARegion *file_execute_region_ensure(ScrArea *area, ARegion *region_prev) { ARegion *region; @@ -149,22 +168,10 @@ static void file_free(SpaceLink *sl) sfile->files = NULL; } - if (sfile->folders_prev) { - folderlist_free(sfile->folders_prev); - MEM_freeN(sfile->folders_prev); - sfile->folders_prev = NULL; - } + folder_history_list_free(sfile); - if (sfile->folders_next) { - folderlist_free(sfile->folders_next); - MEM_freeN(sfile->folders_next); - sfile->folders_next = NULL; - } - - if (sfile->params) { - MEM_freeN(sfile->params); - sfile->params = NULL; - } + MEM_SAFE_FREE(sfile->params); + MEM_SAFE_FREE(sfile->asset_params); if (sfile->layout) { MEM_freeN(sfile->layout); @@ -205,19 +212,20 @@ static SpaceLink *file_duplicate(SpaceLink *sl) sfilen->previews_timer = NULL; sfilen->smoothscroll_timer = NULL; + FileSelectParams *active_params_old = ED_fileselect_get_active_params(sfileo); + if (active_params_old) { + sfilen->files = filelist_new(active_params_old->type); + filelist_setdir(sfilen->files, active_params_old->dir); + } + if (sfileo->params) { - sfilen->files = filelist_new(sfileo->params->type); sfilen->params = MEM_dupallocN(sfileo->params); - filelist_setdir(sfilen->files, sfilen->params->dir); } - - if (sfileo->folders_prev) { - sfilen->folders_prev = folderlist_duplicate(sfileo->folders_prev); + if (sfileo->asset_params) { + sfilen->asset_params = MEM_dupallocN(sfileo->asset_params); } - if (sfileo->folders_next) { - sfilen->folders_next = folderlist_duplicate(sfileo->folders_next); - } + sfilen->folder_histories = folder_history_list_duplicate(&sfileo->folder_histories); if (sfileo->layout) { sfilen->layout = MEM_dupallocN(sfileo->layout); @@ -232,15 +240,30 @@ static void file_ensure_valid_region_state(bContext *C, SpaceFile *sfile, FileSelectParams *params) { - ARegion *region_ui = BKE_area_find_region_type(area, RGN_TYPE_UI); - ARegion *region_props = BKE_area_find_region_type(area, RGN_TYPE_TOOL_PROPS); - ARegion *region_execute = BKE_area_find_region_type(area, RGN_TYPE_EXECUTE); + ARegion *region_tools = BKE_area_find_region_type(area, RGN_TYPE_TOOLS); bool needs_init = false; /* To avoid multiple ED_area_init() calls. */ + BLI_assert(region_tools); + + if (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS) { + ARegion *region_execute = file_execute_region_ensure(area, region_tools); + ARegion *region_props = file_tool_props_region_ensure(area, region_execute); + + /* Hide specific regions by default. */ + region_props->flag |= RGN_FLAG_HIDDEN; + region_execute->flag |= RGN_FLAG_HIDDEN; + + ARegion *region_ui = BKE_area_find_region_type(area, RGN_TYPE_UI); + if (region_ui) { + ED_region_remove(C, area, region_ui); + needs_init = true; + } + } /* If there's an file-operation, ensure we have the option and execute region */ - if (sfile->op && (region_props == NULL)) { - region_execute = file_execute_region_ensure(area, region_ui); - region_props = file_tool_props_region_ensure(area, region_execute); + else if (sfile->op) { + ARegion *region_ui = file_ui_region_ensure(area, region_tools); + ARegion *region_execute = file_execute_region_ensure(area, region_ui); + ARegion *region_props = file_tool_props_region_ensure(area, region_execute); if (params->flag & FILE_HIDE_TOOL_PROPS) { region_props->flag |= RGN_FLAG_HIDDEN; @@ -252,12 +275,19 @@ static void file_ensure_valid_region_state(bContext *C, needs_init = true; } /* If there's _no_ file-operation, ensure we _don't_ have the option and execute region */ - else if ((sfile->op == NULL) && (region_props != NULL)) { - BLI_assert(region_execute != NULL); + else { + ARegion *region_props = BKE_area_find_region_type(area, RGN_TYPE_TOOL_PROPS); + ARegion *region_execute = BKE_area_find_region_type(area, RGN_TYPE_EXECUTE); + ARegion *region_ui = file_ui_region_ensure(area, region_tools); + UNUSED_VARS(region_ui); - ED_region_remove(C, area, region_props); - ED_region_remove(C, area, region_execute); - needs_init = true; + if (region_props) { + BLI_assert(region_execute); + + ED_region_remove(C, area, region_props); + ED_region_remove(C, area, region_execute); + needs_init = true; + } } if (needs_init) { @@ -265,24 +295,42 @@ static void file_ensure_valid_region_state(bContext *C, } } +/** + * Tag the space to recreate the file-list. + */ +static void file_tag_reset_list(ScrArea *area, SpaceFile *sfile) +{ + filelist_tag_force_reset(sfile->files); + ED_area_tag_refresh(area); +} + static void file_refresh(const bContext *C, ScrArea *area) { wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win = CTX_wm_window(C); SpaceFile *sfile = CTX_wm_space_file(C); - FileSelectParams *params = ED_fileselect_get_params(sfile); + FileSelectParams *params = ED_fileselect_ensure_active_params(sfile); + FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile); struct FSMenu *fsmenu = ED_fsmenu_get(); - if (!sfile->folders_prev) { - sfile->folders_prev = folderlist_new(); + fileselect_refresh_params(sfile); + folder_history_list_ensure_for_active_browse_mode(sfile); + + if (sfile->files && (sfile->tags & FILE_TAG_REBUILD_MAIN_FILES) && + filelist_needs_reset_on_main_changes(sfile->files)) { + filelist_tag_force_reset(sfile->files); } + sfile->tags &= ~FILE_TAG_REBUILD_MAIN_FILES; + if (!sfile->files) { sfile->files = filelist_new(params->type); params->highlight_file = -1; /* added this so it opens nicer (ton) */ } + filelist_settype(sfile->files, params->type); filelist_setdir(sfile->files, params->dir); filelist_setrecursion(sfile->files, params->recursion_level); filelist_setsorting(sfile->files, params->sort, params->flag & FILE_SORT_INVERT); + filelist_setlibrary(sfile->files, asset_params ? &asset_params->asset_library : NULL); filelist_setfilter_options( sfile->files, (params->flag & FILE_FILTER) != 0, @@ -290,6 +338,7 @@ static void file_refresh(const bContext *C, ScrArea *area) true, /* Just always hide parent, prefer to not add an extra user option for this. */ params->filter, params->filter_id, + (params->flag & FILE_ASSETS_ONLY) != 0, params->filter_glob, params->filter_search); @@ -300,12 +349,12 @@ static void file_refresh(const bContext *C, ScrArea *area) sfile->bookmarknr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_BOOKMARKS, params->dir); sfile->recentnr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_RECENT, params->dir); - if (filelist_force_reset(sfile->files)) { + if (filelist_needs_force_reset(sfile->files)) { filelist_readjob_stop(wm, CTX_data_scene(C)); filelist_clear(sfile->files); } - if (filelist_empty(sfile->files)) { + if (filelist_needs_reading(sfile->files)) { if (!filelist_pending(sfile->files)) { filelist_readjob_start(sfile->files, C); } @@ -363,8 +412,21 @@ static void file_listener(wmWindow *UNUSED(win), ED_area_tag_refresh(area); } break; + case ND_SPACE_ASSET_PARAMS: + if (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS) { + ED_area_tag_refresh(area); + } + break; } break; + case NC_ASSET: { + if (sfile->files && filelist_needs_reset_on_main_changes(sfile->files)) { + /* Full refresh of the file list if local asset data was changed. Refreshing this view is + * cheap and users expect this to be updated immediately. */ + file_tag_reset_list(area, sfile); + } + break; + } } } @@ -413,7 +475,7 @@ static void file_main_region_message_subscribe(const struct bContext *UNUSED(C), struct wmMsgBus *mbus) { SpaceFile *sfile = area->spacedata.first; - FileSelectParams *params = ED_fileselect_get_params(sfile); + FileSelectParams *params = ED_fileselect_ensure_active_params(sfile); /* This is a bit odd that a region owns the subscriber for an area, * keep for now since all subscribers for WM are regions. * May be worth re-visiting later. */ @@ -442,16 +504,31 @@ static void file_main_region_message_subscribe(const struct bContext *UNUSED(C), } } +static bool file_main_region_needs_refresh_before_draw(SpaceFile *sfile) +{ + /* Needed, because filelist is not initialized on loading */ + if (!sfile->files || filelist_needs_reading(sfile->files)) { + return true; + } + + /* File reading tagged the space because main data changed that may require a filelist reset. */ + if (filelist_needs_reset_on_main_changes(sfile->files) && + (sfile->tags & FILE_TAG_REBUILD_MAIN_FILES)) { + return true; + } + + return false; +} + static void file_main_region_draw(const bContext *C, ARegion *region) { /* draw entirely, view changes should be handled here */ SpaceFile *sfile = CTX_wm_space_file(C); - FileSelectParams *params = ED_fileselect_get_params(sfile); + FileSelectParams *params = ED_fileselect_ensure_active_params(sfile); View2D *v2d = ®ion->v2d; - /* Needed, because filelist is not initialized on loading */ - if (!sfile->files || filelist_empty(sfile->files)) { + if (file_main_region_needs_refresh_before_draw(sfile)) { file_refresh(C, NULL); } @@ -497,7 +574,9 @@ static void file_main_region_draw(const bContext *C, ARegion *region) file_highlight_set(sfile, region, event->x, event->y); } - file_draw_list(C, region); + if (!file_draw_hint_if_invalid(sfile, region)) { + file_draw_list(C, region); + } /* reset view matrix */ UI_view2d_view_restore(C); @@ -681,6 +760,87 @@ static void file_dropboxes(void) WM_dropbox_add(lb, "FILE_OT_filepath_drop", filepath_drop_poll, filepath_drop_copy); } +static int file_space_subtype_get(ScrArea *area) +{ + SpaceFile *sfile = area->spacedata.first; + return sfile->browse_mode; +} + +static void file_space_subtype_set(ScrArea *area, int value) +{ + SpaceFile *sfile = area->spacedata.first; + sfile->browse_mode = value; +} + +static void file_space_subtype_item_extend(bContext *UNUSED(C), + EnumPropertyItem **item, + int *totitem) +{ + RNA_enum_items_add(item, totitem, rna_enum_space_file_browse_mode_items); +} + +static const char *file_context_dir[] = {"active_file", "active_id", NULL}; + +static int /*eContextResult*/ file_context(const bContext *C, + const char *member, + bContextDataResult *result) +{ + bScreen *screen = CTX_wm_screen(C); + SpaceFile *sfile = CTX_wm_space_file(C); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); + + BLI_assert(!ED_area_is_global(CTX_wm_area(C))); + + if (CTX_data_dir(member)) { + CTX_data_dir_set(result, file_context_dir); + return CTX_RESULT_OK; + } + + /* The following member checks return file-list data, check if that needs refreshing first. */ + if (file_main_region_needs_refresh_before_draw(sfile)) { + return CTX_RESULT_NO_DATA; + } + + if (CTX_data_equals(member, "active_file")) { + FileDirEntry *file = filelist_file(sfile->files, params->active_file); + if (file == NULL) { + return CTX_RESULT_NO_DATA; + } + + CTX_data_pointer_set(result, &screen->id, &RNA_FileSelectEntry, file); + return CTX_RESULT_OK; + } + if (CTX_data_equals(member, "id")) { + const FileDirEntry *file = filelist_file(sfile->files, params->active_file); + if (file == NULL) { + return CTX_RESULT_NO_DATA; + } + + ID *id = filelist_file_get_id(file); + if (id == NULL) { + return CTX_RESULT_NO_DATA; + } + + CTX_data_id_pointer_set(result, id); + return CTX_RESULT_OK; + } + + return CTX_RESULT_MEMBER_NOT_FOUND; +} + +static void file_id_remap(ScrArea *area, SpaceLink *sl, ID *UNUSED(old_id), ID *UNUSED(new_id)) +{ + SpaceFile *sfile = (SpaceFile *)sl; + + /* If the file shows main data (IDs), tag it for reset. */ + if (sfile->files && filelist_needs_reset_on_main_changes(sfile->files)) { + /* Full refresh of the file list if main data was changed, don't even attempt remap pointers. + * We could give file list types a id-remap callback, but it's probably not worth it. + * Refreshing local file lists is relatively cheap. */ + file_tag_reset_list(area, sfile); + } +} + /* only called once, from space/spacetypes.c */ void ED_spacetype_file(void) { @@ -700,6 +860,11 @@ void ED_spacetype_file(void) st->operatortypes = file_operatortypes; st->keymap = file_keymap; st->dropboxes = file_dropboxes; + st->space_subtype_item_extend = file_space_subtype_item_extend; + st->space_subtype_get = file_space_subtype_get; + st->space_subtype_set = file_space_subtype_set; + st->context = file_context; + st->id_remap = file_id_remap; /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype file region"); diff --git a/source/blender/editors/space_graph/CMakeLists.txt b/source/blender/editors/space_graph/CMakeLists.txt index 414e5c87f5a..2a795dd954c 100644 --- a/source/blender/editors/space_graph/CMakeLists.txt +++ b/source/blender/editors/space_graph/CMakeLists.txt @@ -34,8 +34,8 @@ set(SRC graph_draw.c graph_edit.c graph_ops.c - graph_slider_ops.c graph_select.c + graph_slider_ops.c graph_utils.c graph_view.c space_graph.c diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index ae34cd6cf6d..e56d71913d6 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -72,7 +72,9 @@ /* ************************************************************************** */ /* INSERT DUPLICATE AND BAKE KEYFRAMES */ -/* ******************** Insert Keyframes Operator ************************* */ +/* -------------------------------------------------------------------- */ +/** \name Insert Keyframes Operator + * \{ */ /* Mode defines for insert keyframes tool. */ typedef enum eGraphKeys_InsertKey_Types { @@ -290,7 +292,11 @@ void GRAPH_OT_keyframe_insert(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", prop_graphkeys_insertkey_types, 0, "Type", ""); } -/* ******************** Click-Insert Keyframes Operator ************************* */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Click-Insert Keyframes Operator + * \{ */ static int graphkeys_click_insert_exec(bContext *C, wmOperator *op) { @@ -444,8 +450,13 @@ void GRAPH_OT_click_insert(wmOperatorType *ot) "Extend selection instead of deselecting everything first"); } -/* ******************** Copy/Paste Keyframes Operator ************************* */ -/* NOTE: the backend code for this is shared with the dopesheet editor */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Copy/Paste Keyframes Operator + * + * \note the back-end code for this is shared with the dope-sheet editor. + * \{ */ static short copy_graph_keys(bAnimContext *ac) { @@ -605,7 +616,11 @@ void GRAPH_OT_paste(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/* ******************** Duplicate Keyframes Operator ************************* */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Duplicate Keyframes Operator + * \{ */ static void duplicate_graph_keys(bAnimContext *ac) { @@ -667,7 +682,11 @@ void GRAPH_OT_duplicate(wmOperatorType *ot) RNA_def_enum(ot->srna, "mode", rna_enum_transform_mode_types, TFM_TRANSLATION, "Mode", ""); } -/* ******************** Delete Keyframes Operator ************************* */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Delete Keyframes Operator + * \{ */ static bool delete_graph_keys(bAnimContext *ac) { @@ -746,7 +765,11 @@ void GRAPH_OT_delete(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ******************** Clean Keyframes Operator ************************* */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Clean Keyframes Operator + * \{ */ static void clean_graph_keys(bAnimContext *ac, float thresh, bool clean_chan) { @@ -816,8 +839,13 @@ void GRAPH_OT_clean(wmOperatorType *ot) RNA_def_boolean(ot->srna, "channels", false, "Channels", ""); } -/* ******************** Bake F-Curve Operator *********************** */ -/* This operator bakes the data of the selected F-Curves to F-Points */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Bake F-Curve Operator + * + * This operator bakes the data of the selected F-Curves to F-Points. + * \{ */ /* Bake each F-Curve into a set of samples. */ static void bake_graph_curves(bAnimContext *ac, int start, int end) @@ -899,8 +927,13 @@ void GRAPH_OT_bake(wmOperatorType *ot) /* TODO: add props for start/end frames (Joshua Leung 2009) */ } -/* ******************** Un-Bake F-Curve Operator *********************** */ -/* This operator unbakes the data of the selected F-Points to F-Curves. */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Un-Bake F-Curve Operator + * + * This operator un-bakes the data of the selected F-Points to F-Curves. + * \{ */ /* Un-Bake F-Points into F-Curves. */ static void unbake_graph_curves(bAnimContext *ac, int start, int end) @@ -970,8 +1003,13 @@ void GRAPH_OT_unbake(wmOperatorType *ot) #ifdef WITH_AUDASPACE -/* ******************** Sound Bake F-Curve Operator *********************** */ -/* This operator bakes the given sound to the selected F-Curves */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Sound Bake F-Curve Operator + * + * This operator bakes the given sound to the selected F-Curves. + * \{ */ /* ------------------- */ @@ -1204,10 +1242,14 @@ void GRAPH_OT_sound_bake(wmOperatorType *ot) 0.1); } -/* ******************** Sample Keyframes Operator *********************** */ -/* This operator 'bakes' the values of the curve into new keyframes between pairs +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Sample Keyframes Operator + * + * This operator 'bakes' the values of the curve into new keyframes between pairs * of selected keyframes. It is useful for creating keyframes for tweaking overlap. - */ + * \{ */ /* Evaluates the curves between each selected keyframe on each frame, and keys the value. */ static void sample_graph_keys(bAnimContext *ac) @@ -1267,10 +1309,14 @@ void GRAPH_OT_sample(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ + /* ************************************************************************** */ /* EXTRAPOLATION MODE AND KEYFRAME HANDLE SETTINGS */ -/* ******************** Set Extrapolation-Type Operator *********************** */ +/* -------------------------------------------------------------------- */ +/** \name Set Extrapolation-Type Operator + * \{ */ /* Defines for make/clear cyclic extrapolation tools. */ #define MAKE_CYCLIC_EXPO -1 @@ -1400,7 +1446,11 @@ void GRAPH_OT_extrapolation_type(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", prop_graphkeys_expo_types, 0, "Type", ""); } -/* ******************** Set Interpolation-Type Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Set Interpolation-Type Operator + * \{ */ /* This function is responsible for setting interpolation mode for keyframes. */ static void setipo_graph_keys(bAnimContext *ac, short mode) @@ -1474,7 +1524,11 @@ void GRAPH_OT_interpolation_type(wmOperatorType *ot) ot->srna, "type", rna_enum_beztriple_interpolation_mode_items, 0, "Type", ""); } -/* ******************** Set Easing Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Set Easing Operator + * \{ */ static void seteasing_graph_keys(bAnimContext *ac, short mode) { @@ -1545,7 +1599,11 @@ void GRAPH_OT_easing_type(wmOperatorType *ot) ot->srna, "type", rna_enum_beztriple_interpolation_easing_items, 0, "Type", ""); } -/* ******************** Set Handle-Type Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Set Handle-Type Operator + * \{ */ /* This function is responsible for setting handle-type of selected keyframes. */ static void sethandles_graph_keys(bAnimContext *ac, short mode) @@ -1624,15 +1682,19 @@ void GRAPH_OT_handle_type(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_keyframe_handle_type_items, 0, "Type", ""); } +/** \} */ + /* ************************************************************************** */ /* EULER FILTER */ -/* ***************** 'Euler Filter' Operator **************************** */ -/* Euler filter tools (as seen in Maya), are necessary for working with 'baked' +/* -------------------------------------------------------------------- */ +/** \name 'Euler Filter' Operator + * + * Euler filter tools (as seen in Maya), are necessary for working with 'baked' * rotation curves (with Euler rotations). The main purpose of such tools is to * resolve any discontinuities that may arise in the curves due to the clamping * of values to -180 degrees to 180 degrees. - */ + * \{ */ /* Set of three euler-rotation F-Curves. */ typedef struct tEulerFilter { @@ -1955,10 +2017,14 @@ void GRAPH_OT_euler_filter(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ + /* ************************************************************************** */ /* SNAPPING */ -/* ***************** Jump to Selected Frames Operator *********************** */ +/* -------------------------------------------------------------------- */ +/** \name Jump to Selected Frames Operator + * \{ */ static bool graphkeys_framejump_poll(bContext *C) { @@ -2110,7 +2176,11 @@ void GRAPH_OT_snap_cursor_value(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ******************** Snap Keyframes Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Snap Keyframes Operator + * \{ */ /* Defines for snap keyframes tool. */ static const EnumPropertyItem prop_graphkeys_snap_types[] = { @@ -2262,7 +2332,11 @@ void GRAPH_OT_snap(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", prop_graphkeys_snap_types, 0, "Type", ""); } -/* ******************** Mirror Keyframes Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Mirror Keyframes Operator + * \{ */ /* Defines for mirror keyframes tool. */ static const EnumPropertyItem prop_graphkeys_mirror_types[] = { @@ -2280,12 +2354,12 @@ static const EnumPropertyItem prop_graphkeys_mirror_types[] = { {GRAPHKEYS_MIRROR_YAXIS, "YAXIS", 0, - "By Times Over Time=0", + "By Times Over Zero Time", "Flip times of selected keyframes, effectively reversing the order they appear in"}, {GRAPHKEYS_MIRROR_XAXIS, "XAXIS", 0, - "By Values Over Value=0", + "By Values Over Zero Value", "Flip values of selected keyframes (i.e. negative values become positive, and vice versa)"}, {GRAPHKEYS_MIRROR_MARKER, "MARKER", @@ -2421,7 +2495,11 @@ void GRAPH_OT_mirror(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", prop_graphkeys_mirror_types, 0, "Type", ""); } -/* ******************** Smooth Keyframes Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Smooth Keyframes Operator + * \{ */ static int graphkeys_smooth_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -2475,10 +2553,14 @@ void GRAPH_OT_smooth(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ + /* ************************************************************************** */ /* F-CURVE MODIFIERS */ -/* ******************** Add F-Modifier Operator *********************** */ +/* -------------------------------------------------------------------- */ +/** \name Add F-Modifier Operator + * \{ */ static const EnumPropertyItem *graph_fmodifier_itemf(bContext *C, PointerRNA *UNUSED(ptr), @@ -2596,7 +2678,11 @@ void GRAPH_OT_fmodifier_add(wmOperatorType *ot) ot->srna, "only_active", 1, "Only Active", "Only add F-Modifier to active F-Curve"); } -/* ******************** Copy F-Modifiers Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Copy F-Modifiers Operator + * \{ */ static int graph_fmodifier_copy_exec(bContext *C, wmOperator *op) { @@ -2658,7 +2744,11 @@ void GRAPH_OT_fmodifier_copy(wmOperatorType *ot) #endif } -/* ******************** Paste F-Modifiers Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Paste F-Modifiers Operator + * \{ */ static int graph_fmodifier_paste_exec(bContext *C, wmOperator *op) { @@ -2746,10 +2836,14 @@ void GRAPH_OT_fmodifier_paste(wmOperatorType *ot) "Replace existing F-Modifiers, instead of just appending to the end of the existing list"); } +/** \} */ + /* ************************************************************************** */ /* Drivers */ -/* ******************** Copy Driver Vars Operator *********************** */ +/* -------------------------------------------------------------------- */ +/** \name Copy Driver Variables Operator + * \{ */ static int graph_driver_vars_copy_exec(bContext *C, wmOperator *op) { @@ -2786,7 +2880,11 @@ void GRAPH_OT_driver_variables_copy(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ******************** Paste Driver Vars Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Paste Driver Variables Operator + * \{ */ static int graph_driver_vars_paste_exec(bContext *C, wmOperator *op) { @@ -2838,7 +2936,11 @@ void GRAPH_OT_driver_variables_paste(wmOperatorType *ot) "existing list"); } -/* ************************************************************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Delete Invalid Drivers Operator + * \{ */ static int graph_driver_delete_invalid_exec(bContext *C, wmOperator *op) { @@ -2926,3 +3028,5 @@ void GRAPH_OT_driver_delete_invalid(wmOperatorType *ot) /* Flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } + +/** \} */ diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c index 12035ab6b61..4ab4ef518fb 100644 --- a/source/blender/editors/space_graph/graph_select.c +++ b/source/blender/editors/space_graph/graph_select.c @@ -1288,8 +1288,8 @@ void GRAPH_OT_select_less(wmOperatorType *ot) /* defines for left-right select tool */ static const EnumPropertyItem prop_graphkeys_leftright_select_types[] = { {GRAPHKEYS_LRSEL_TEST, "CHECK", 0, "Check if Select Left or Right", ""}, - {GRAPHKEYS_LRSEL_LEFT, "LEFT", 0, "Before current frame", ""}, - {GRAPHKEYS_LRSEL_RIGHT, "RIGHT", 0, "After current frame", ""}, + {GRAPHKEYS_LRSEL_LEFT, "LEFT", 0, "Before Current Frame", ""}, + {GRAPHKEYS_LRSEL_RIGHT, "RIGHT", 0, "After Current Frame", ""}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/editors/space_graph/graph_view.c b/source/blender/editors/space_graph/graph_view.c index 0b9ba3762a3..cde0dab3503 100644 --- a/source/blender/editors/space_graph/graph_view.c +++ b/source/blender/editors/space_graph/graph_view.c @@ -533,4 +533,4 @@ void GRAPH_OT_ghost_curves_clear(wmOperatorType *ot) /* Flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -}
\ No newline at end of file +} diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index c0c0280959c..1996f05b36a 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -86,26 +86,9 @@ static void ui_imageuser_slot_menu(bContext *UNUSED(C), uiLayout *layout, void * { uiBlock *block = uiLayoutGetBlock(layout); Image *image = image_p; - int slot_id; - uiDefBut(block, - UI_BTYPE_LABEL, - 0, - IFACE_("Slot"), - 0, - 0, - UI_UNIT_X * 5, - UI_UNIT_Y, - NULL, - 0.0, - 0.0, - 0, - 0, - ""); - uiItemS(layout); - - slot_id = BLI_listbase_count(&image->renderslots) - 1; - for (RenderSlot *slot = image->renderslots.last; slot; slot = slot->prev) { + int slot_id; + LISTBASE_FOREACH_INDEX (RenderSlot *, slot, &image->renderslots, slot_id) { char str[64]; if (slot->name[0] != '\0') { BLI_strncpy(str, slot->name, sizeof(str)); @@ -127,8 +110,23 @@ static void ui_imageuser_slot_menu(bContext *UNUSED(C), uiLayout *layout, void * 0, -1, ""); - slot_id--; } + + uiItemS(layout); + uiDefBut(block, + UI_BTYPE_LABEL, + 0, + IFACE_("Slot"), + 0, + 0, + UI_UNIT_X * 5, + UI_UNIT_Y, + NULL, + 0.0, + 0.0, + 0, + 0, + ""); } static bool ui_imageuser_slot_menu_step(bContext *C, int direction, void *image_p) @@ -175,14 +173,9 @@ static void ui_imageuser_layer_menu(bContext *UNUSED(C), uiLayout *layout, void Image *image = rnd_data->image; ImageUser *iuser = rnd_data->iuser; Scene *scene = iuser->scene; - RenderResult *rr; - RenderLayer *rl; - RenderLayer rl_fake = {NULL}; - const char *fake_name; - int nr; - /* may have been freed since drawing */ - rr = BKE_image_acquire_renderresult(scene, image); + /* May have been freed since drawing. */ + RenderResult *rr = BKE_image_acquire_renderresult(scene, image); if (UNLIKELY(rr == NULL)) { return; } @@ -190,32 +183,26 @@ static void ui_imageuser_layer_menu(bContext *UNUSED(C), uiLayout *layout, void UI_block_layout_set_current(block, layout); uiLayoutColumn(layout, false); - uiDefBut(block, - UI_BTYPE_LABEL, - 0, - IFACE_("Layer"), - 0, - 0, - UI_UNIT_X * 5, - UI_UNIT_Y, - NULL, - 0.0, - 0.0, - 0, - 0, - ""); - uiItemS(layout); - - nr = BLI_listbase_count(&rr->layers) - 1; - fake_name = ui_imageuser_layer_fake_name(rr); - + const char *fake_name = ui_imageuser_layer_fake_name(rr); if (fake_name) { - BLI_strncpy(rl_fake.name, fake_name, sizeof(rl_fake.name)); - nr += 1; + uiDefButS(block, + UI_BTYPE_BUT_MENU, + B_NOP, + fake_name, + 0, + 0, + UI_UNIT_X * 5, + UI_UNIT_X, + &iuser->layer, + 0.0, + 0.0, + 0, + -1, + ""); } - for (rl = rr->layers.last; rl; rl = rl->prev, nr--) { - final: + int nr = fake_name ? 1 : 0; + for (RenderLayer *rl = rr->layers.first; rl; rl = rl->next, nr++) { uiDefButS(block, UI_BTYPE_BUT_MENU, B_NOP, @@ -232,13 +219,21 @@ static void ui_imageuser_layer_menu(bContext *UNUSED(C), uiLayout *layout, void ""); } - if (fake_name) { - fake_name = NULL; - rl = &rl_fake; - goto final; - } - - BLI_assert(nr == -1); + uiItemS(layout); + uiDefBut(block, + UI_BTYPE_LABEL, + 0, + IFACE_("Layer"), + 0, + 0, + UI_UNIT_X * 5, + UI_UNIT_Y, + NULL, + 0.0, + 0.0, + 0, + 0, + ""); BKE_image_release_renderresult(scene, image); } @@ -268,23 +263,6 @@ static void ui_imageuser_pass_menu(bContext *UNUSED(C), uiLayout *layout, void * UI_block_layout_set_current(block, layout); uiLayoutColumn(layout, false); - uiDefBut(block, - UI_BTYPE_LABEL, - 0, - IFACE_("Pass"), - 0, - 0, - UI_UNIT_X * 5, - UI_UNIT_Y, - NULL, - 0.0, - 0.0, - 0, - 0, - ""); - - uiItemS(layout); - nr = (rl == NULL) ? 1 : 0; ListBase added_passes; @@ -315,6 +293,22 @@ static void ui_imageuser_pass_menu(bContext *UNUSED(C), uiLayout *layout, void * ""); } + uiItemS(layout); + uiDefBut(block, + UI_BTYPE_LABEL, + 0, + IFACE_("Pass"), + 0, + 0, + UI_UNIT_X * 5, + UI_UNIT_Y, + NULL, + 0.0, + 0.0, + 0, + 0, + ""); + BLI_freelistN(&added_passes); BKE_image_release_renderresult(scene, image); @@ -806,7 +800,8 @@ void uiTemplateImage(uiLayout *layout, C, ptr, propname, - ima ? NULL : "IMAGE_OT_new", + "IMAGE_OT_new", + NULL, "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c index 180f1fb183c..c26f92c5463 100644 --- a/source/blender/editors/space_image/image_edit.c +++ b/source/blender/editors/space_image/image_edit.c @@ -407,6 +407,9 @@ bool ED_image_slot_cycle(struct Image *image, int direction) image->render_slot = ((cur == 1) ? 0 : 1); } + if ((cur != image->render_slot)) { + image->gpuflag |= IMA_GPU_REFRESH; + } return (cur != image->render_slot); } diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 0fa48059cdc..a2c0819dc60 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -2649,7 +2649,7 @@ void IMAGE_OT_new(wmOperatorType *ot) "Generated Type", "Fill the image with a grid for UV map testing"); RNA_def_boolean( - ot->srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth"); + ot->srna, "float", 0, "32-bit Float", "Create image with 32-bit floating-point bit depth"); RNA_def_property_flag(prop, PROP_HIDDEN); prop = RNA_def_boolean( ot->srna, "use_stereo_3d", 0, "Stereo 3D", "Create an image with left and right views"); @@ -3737,7 +3737,7 @@ static void def_fill_tile(StructOrFunctionRNA *srna) /* Only needed when filling the first tile. */ RNA_def_boolean( - srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth"); + srna, "float", 0, "32-bit Float", "Create image with 32-bit floating-point bit depth"); RNA_def_boolean(srna, "alpha", 1, "Alpha", "Create an image with an alpha channel"); } diff --git a/source/blender/editors/space_info/info_report.c b/source/blender/editors/space_info/info_report.c index 3ba088018c3..7dd8382c8ef 100644 --- a/source/blender/editors/space_info/info_report.c +++ b/source/blender/editors/space_info/info_report.c @@ -396,7 +396,7 @@ void INFO_OT_report_copy(wmOperatorType *ot) { /* identifiers */ ot->name = "Copy Reports to Clipboard"; - ot->description = "Copy selected reports to Clipboard"; + ot->description = "Copy selected reports to clipboard"; ot->idname = "INFO_OT_report_copy"; /* api callbacks */ diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c index 083fd641dc1..218fc3b7141 100644 --- a/source/blender/editors/space_nla/nla_buttons.c +++ b/source/blender/editors/space_nla/nla_buttons.c @@ -292,8 +292,9 @@ static void nla_panel_animdata(const bContext *C, Panel *panel) (bContext *)C, &adt_ptr, "action", - "ACTION_OT_new", NULL, + "ACTION_OT_new", + "ACTION_OT_duplicate_assign", "NLA_OT_action_unlink", UI_TEMPLATE_ID_FILTER_ALL, false, @@ -345,7 +346,7 @@ static void nla_panel_stripname(const bContext *C, Panel *panel) uiItemR(row, &strip_ptr, "name", 0, "", ICON_NLA); - UI_block_emboss_set(block, UI_EMBOSS_NONE); + UI_block_emboss_set(block, UI_EMBOSS_NONE_OR_STATUS); uiItemR(row, &strip_ptr, "mute", 0, "", ICON_NONE); UI_block_emboss_set(block, UI_EMBOSS); } diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c index 561de5e82a6..9832ca975cf 100644 --- a/source/blender/editors/space_nla/nla_channels.c +++ b/source/blender/editors/space_nla/nla_channels.c @@ -292,7 +292,7 @@ static int mouse_nla_channels( /* TODO: make this use the operator instead of calling the function directly * however, calling the operator requires that we supply the args, * and that works with proper buttons only */ - BKE_nla_action_pushdown(adt); + BKE_nla_action_pushdown(adt, ID_IS_OVERRIDE_LIBRARY(ale->id)); } else { /* when in tweakmode, this button becomes the toggle for mapped editing */ @@ -516,7 +516,7 @@ static int nlachannels_pushdown_exec(bContext *C, wmOperator *op) } /* 'push-down' action - only usable when not in TweakMode */ - BKE_nla_action_pushdown(adt); + BKE_nla_action_pushdown(adt, ID_IS_OVERRIDE_LIBRARY(id)); struct Main *bmain = CTX_data_main(C); DEG_id_tag_update_ex(bmain, id, ID_RECALC_ANIMATION); @@ -648,19 +648,21 @@ bool nlaedit_add_tracks_existing(bAnimContext *ac, bool above_sel) NlaTrack *nlt = (NlaTrack *)ale->data; AnimData *adt = ale->adt; + const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ale->id); + /* check if just adding a new track above this one, * or whether we're adding a new one to the top of the stack that this one belongs to */ if (above_sel) { /* just add a new one above this one */ - BKE_nlatrack_add(adt, nlt); + BKE_nlatrack_add(adt, nlt, is_liboverride); ale->update = ANIM_UPDATE_DEPS; added = true; } else if ((lastAdt == NULL) || (adt != lastAdt)) { /* add one track to the top of the owning AnimData's stack, * then don't add anymore to this stack */ - BKE_nlatrack_add(adt, NULL); + BKE_nlatrack_add(adt, NULL, is_liboverride); lastAdt = adt; ale->update = ANIM_UPDATE_DEPS; added = true; @@ -698,7 +700,7 @@ bool nlaedit_add_tracks_empty(bAnimContext *ac) /* ensure it is empty */ if (BLI_listbase_is_empty(&adt->nla_tracks)) { /* add new track to this AnimData block then */ - BKE_nlatrack_add(adt, NULL); + BKE_nlatrack_add(adt, NULL, ID_IS_OVERRIDE_LIBRARY(ale->id)); ale->update = ANIM_UPDATE_DEPS; added = true; } @@ -796,6 +798,11 @@ static int nlaedit_delete_tracks_exec(bContext *C, wmOperator *UNUSED(op)) NlaTrack *nlt = (NlaTrack *)ale->data; AnimData *adt = ale->adt; + if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) { + /* No deletion of non-local tracks of override data. */ + continue; + } + /* if track is currently 'solo', then AnimData should have its * 'has solo' flag disabled */ diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c index ed8e5ad76e9..3fa1b614a03 100644 --- a/source/blender/editors/space_nla/nla_edit.c +++ b/source/blender/editors/space_nla/nla_edit.c @@ -649,6 +649,7 @@ static int nlaedit_add_actionclip_exec(bContext *C, wmOperator *op) NlaTrack *nlt = (NlaTrack *)ale->data; AnimData *adt = ale->adt; NlaStrip *strip = NULL; + const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ale->id); /* Sanity check: only apply actions of the right type for this ID. * NOTE: in the case that this hasn't been set, @@ -671,12 +672,12 @@ static int nlaedit_add_actionclip_exec(bContext *C, wmOperator *op) strip->start = cfra; /* firstly try adding strip to our current track, but if that fails, add to a new track */ - if (BKE_nlatrack_add_strip(nlt, strip) == 0) { + if (BKE_nlatrack_add_strip(nlt, strip, is_liboverride) == 0) { /* trying to add to the current failed (no space), * so add a new track to the stack, and add to that... */ - nlt = BKE_nlatrack_add(adt, NULL); - BKE_nlatrack_add_strip(nlt, strip); + nlt = BKE_nlatrack_add(adt, NULL, is_liboverride); + BKE_nlatrack_add_strip(nlt, strip, is_liboverride); } /* auto-name it */ @@ -886,6 +887,7 @@ static int nlaedit_add_sound_exec(bContext *C, wmOperator *UNUSED(op)) AnimData *adt = ale->adt; NlaTrack *nlt = (NlaTrack *)ale->data; NlaStrip *strip; + const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ale->id); /* does this belong to speaker - assumed to live on Object level only */ if ((GS(ale->id->name) != ID_OB) || (ob->type != OB_SPEAKER)) { @@ -899,12 +901,12 @@ static int nlaedit_add_sound_exec(bContext *C, wmOperator *UNUSED(op)) strip->end += cfra; /* firstly try adding strip to our current track, but if that fails, add to a new track */ - if (BKE_nlatrack_add_strip(nlt, strip) == 0) { + if (BKE_nlatrack_add_strip(nlt, strip, is_liboverride) == 0) { /* trying to add to the current failed (no space), * so add a new track to the stack, and add to that... */ - nlt = BKE_nlatrack_add(adt, NULL); - BKE_nlatrack_add_strip(nlt, strip); + nlt = BKE_nlatrack_add(adt, NULL, is_liboverride); + BKE_nlatrack_add_strip(nlt, strip, is_liboverride); } /* auto-name it */ @@ -966,6 +968,11 @@ static int nlaedit_add_meta_exec(bContext *C, wmOperator *UNUSED(op)) AnimData *adt = ale->adt; NlaStrip *strip; + if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) { + /* No making metastrips in non-local tracks of override data. */ + continue; + } + /* create meta-strips from the continuous chains of selected strips */ BKE_nlastrips_make_metas(&nlt->strips, 0); @@ -1030,6 +1037,11 @@ static int nlaedit_remove_meta_exec(bContext *C, wmOperator *UNUSED(op)) for (ale = anim_data.first; ale; ale = ale->next) { NlaTrack *nlt = (NlaTrack *)ale->data; + if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) { + /* No removing metastrips from non-local tracks of override data. */ + continue; + } + /* clear all selected meta-strips, regardless of whether they are temporary or not */ BKE_nlastrips_clear_metas(&nlt->strips, 1, 0); @@ -1096,6 +1108,11 @@ static int nlaedit_duplicate_exec(bContext *C, wmOperator *op) NlaStrip *strip, *nstrip, *next; NlaTrack *track; + /* Note: We allow this operator in override context because it is almost always (from possible + * default user interactions) paired with the transform one, which will ensure that the new + * strip ends up in a valid (local) track. */ + + const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ale->id); for (strip = nlt->strips.first; strip; strip = next) { next = strip->next; @@ -1106,13 +1123,13 @@ static int nlaedit_duplicate_exec(bContext *C, wmOperator *op) /* in case there's no space in the track above, * or we haven't got a reference to it yet, try adding */ - if (BKE_nlatrack_add_strip(nlt->next, nstrip) == 0) { + if (BKE_nlatrack_add_strip(nlt->next, nstrip, is_liboverride) == 0) { /* need to add a new track above the one above the current one * - if the current one is the last one, nlt->next will be NULL, which defaults to adding * at the top of the stack anyway... */ - track = BKE_nlatrack_add(adt, nlt->next); - BKE_nlatrack_add_strip(track, nstrip); + track = BKE_nlatrack_add(adt, nlt->next, is_liboverride); + BKE_nlatrack_add_strip(track, nstrip, is_liboverride); } /* deselect the original and the active flag */ @@ -1209,6 +1226,11 @@ static int nlaedit_delete_exec(bContext *C, wmOperator *UNUSED(op)) NlaTrack *nlt = (NlaTrack *)ale->data; NlaStrip *strip, *nstrip; + if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) { + /* No deletion of strips in non-local tracks of override data. */ + continue; + } + for (strip = nlt->strips.first; strip; strip = nstrip) { nstrip = strip->next; @@ -1359,6 +1381,11 @@ static int nlaedit_split_exec(bContext *C, wmOperator *UNUSED(op)) AnimData *adt = ale->adt; NlaStrip *strip, *next; + if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) { + /* No splitting of strips in non-local tracks of override data. */ + continue; + } + for (strip = nlt->strips.first; strip; strip = next) { next = strip->next; @@ -1502,6 +1529,12 @@ static int nlaedit_swap_exec(bContext *C, wmOperator *op) NlaStrip *strip, *stripN = NULL; NlaStrip *area = NULL, *sb = NULL; + const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ale->id); + + if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) { + /* No re-ordering of strips whithin non-local tracks of override data. */ + continue; + } /* make temporary metastrips so that entire islands of selections can be moved around */ BKE_nlastrips_make_metas(&nlt->strips, 1); @@ -1610,8 +1643,8 @@ static int nlaedit_swap_exec(bContext *C, wmOperator *op) } /* add strips back to track now */ - BKE_nlatrack_add_strip(nlt, area); - BKE_nlatrack_add_strip(nlt, sb); + BKE_nlatrack_add_strip(nlt, area, is_liboverride); + BKE_nlatrack_add_strip(nlt, sb, is_liboverride); } /* clear (temp) metastrips */ @@ -1674,11 +1707,19 @@ static int nlaedit_move_up_exec(bContext *C, wmOperator *UNUSED(op)) NlaTrack *nltn = nlt->next; NlaStrip *strip, *stripn; + const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ale->id); + /* if this track has no tracks after it, skip for now... */ if (nltn == NULL) { continue; } + if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt) || + BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nltn)) { + /* No moving of strips in non-local tracks of override data. */ + continue; + } + /* for every selected strip, try to move */ for (strip = nlt->strips.first; strip; strip = stripn) { stripn = strip->next; @@ -1689,7 +1730,7 @@ static int nlaedit_move_up_exec(bContext *C, wmOperator *UNUSED(op)) /* remove from its current track, and add to the one above * (it 'should' work, so no need to worry) */ BLI_remlink(&nlt->strips, strip); - BKE_nlatrack_add_strip(nltn, strip); + BKE_nlatrack_add_strip(nltn, strip, is_liboverride); } } } @@ -1751,11 +1792,19 @@ static int nlaedit_move_down_exec(bContext *C, wmOperator *UNUSED(op)) NlaTrack *nltp = nlt->prev; NlaStrip *strip, *stripn; + const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ale->id); + /* if this track has no tracks before it, skip for now... */ if (nltp == NULL) { continue; } + if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt) || + BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nltp)) { + /* No moving of strips in non-local tracks of override data. */ + continue; + } + /* for every selected strip, try to move */ for (strip = nlt->strips.first; strip; strip = stripn) { stripn = strip->next; @@ -1766,7 +1815,7 @@ static int nlaedit_move_down_exec(bContext *C, wmOperator *UNUSED(op)) /* remove from its current track, and add to the one above * (it 'should' work, so no need to worry) */ BLI_remlink(&nlt->strips, strip); - BKE_nlatrack_add_strip(nltp, strip); + BKE_nlatrack_add_strip(nltp, strip, is_liboverride); } } } @@ -2023,11 +2072,11 @@ static int nlaedit_apply_scale_exec(bContext *C, wmOperator *UNUSED(op)) /* strip must be selected, and must be action-clip only * (transitions don't have scale) */ if ((strip->flag & NLASTRIP_FLAG_SELECT) && (strip->type == NLASTRIP_TYPE_CLIP)) { - /* if the referenced action is used by other strips, - * make this strip use its own copy */ - if (strip->act == NULL) { + if (strip->act == NULL || ID_IS_OVERRIDE_LIBRARY(strip->act) || ID_IS_LINKED(strip->act)) { continue; } + /* if the referenced action is used by other strips, + * make this strip use its own copy */ if (strip->act->id.us > 1) { /* make a copy of the Action to work on */ bAction *act = (bAction *)BKE_id_copy(bmain, &strip->act->id); @@ -2200,6 +2249,8 @@ static int nlaedit_snap_exec(bContext *C, wmOperator *op) NlaStrip *strip, *stripn; NlaTrack *track; + const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ale->id); + /* create meta-strips from the continuous chains of selected strips */ BKE_nlastrips_make_metas(&nlt->strips, 1); @@ -2255,10 +2306,10 @@ static int nlaedit_snap_exec(bContext *C, wmOperator *op) BLI_remlink(&tmp_strips, strip); /* in case there's no space in the current track, try adding */ - if (BKE_nlatrack_add_strip(nlt, strip) == 0) { + if (BKE_nlatrack_add_strip(nlt, strip, is_liboverride) == 0) { /* need to add a new track above the current one */ - track = BKE_nlatrack_add(adt, nlt); - BKE_nlatrack_add_strip(track, strip); + track = BKE_nlatrack_add(adt, nlt, is_liboverride); + BKE_nlatrack_add_strip(track, strip, is_liboverride); /* clear temp meta-strips on this new track, * as we may not be able to get back to it */ @@ -2375,6 +2426,11 @@ static int nla_fmodifier_add_exec(bContext *C, wmOperator *op) NlaTrack *nlt = (NlaTrack *)ale->data; NlaStrip *strip; + if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) { + /* No adding f-modifiers to strips in non-local tracks of override data. */ + continue; + } + for (strip = nlt->strips.first; strip; strip = strip->next) { /* can F-Modifier be added to the current strip? */ if (active_only) { @@ -2552,6 +2608,11 @@ static int nla_fmodifier_paste_exec(bContext *C, wmOperator *op) NlaTrack *nlt = (NlaTrack *)ale->data; NlaStrip *strip; + if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) { + /* No pasting in non-local tracks of override data. */ + continue; + } + for (strip = nlt->strips.first; strip; strip = strip->next) { /* can F-Modifier be added to the current strip? */ if (active_only) { diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt index d8f31161c20..f4a3bb96aeb 100644 --- a/source/blender/editors/space_node/CMakeLists.txt +++ b/source/blender/editors/space_node/CMakeLists.txt @@ -21,6 +21,7 @@ set(INC ../../blenkernel ../../blenlib ../../blentranslation + ../../compositor ../../depsgraph ../../draw ../../gpu @@ -29,7 +30,6 @@ set(INC ../../makesrna ../../nodes ../../render - ../../compositor ../../windowmanager ../../../../intern/glew-mx ../../../../intern/guardedalloc diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 84e7a74fab3..0ce31707204 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -203,42 +203,6 @@ static void node_buts_normal(uiLayout *layout, bContext *UNUSED(C), PointerRNA * uiItemR(layout, &sockptr, "default_value", DEFAULT_FLAGS, "", ICON_NONE); } -#if 0 /* not used in 2.5x yet */ -static void node_browse_tex_cb(bContext *C, void *ntree_v, void *node_v) -{ - Main *bmain = CTX_data_main(C); - bNodeTree *ntree = ntree_v; - bNode *node = node_v; - Tex *tex; - - if (node->menunr < 1) { - return; - } - - if (node->id) { - id_us_min(node->id); - node->id = NULL; - } - tex = BLI_findlink(&bmain->tex, node->menunr - 1); - - node->id = &tex->id; - id_us_plus(node->id); - BLI_strncpy(node->name, node->id->name + 2, sizeof(node->name)); - - nodeSetActive(ntree, node); - - if (ntree->type == NTREE_TEXTURE) { - ntreeTexCheckCyclics(ntree); - } - - // allqueue(REDRAWBUTSSHADING, 0); - // allqueue(REDRAWNODE, 0); - NodeTagChanged(ntree, node); - - node->menunr = 0; -} -#endif - static void node_buts_texture(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { bNode *node = ptr->data; @@ -771,6 +735,7 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA ptr, "image", "IMAGE_OT_new", + NULL, "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, @@ -808,6 +773,7 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin ptr, "image", "IMAGE_OT_new", + NULL, "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, @@ -1395,6 +1361,7 @@ static void node_composit_buts_image(uiLayout *layout, bContext *C, PointerRNA * ptr, "image", "IMAGE_OT_new", + NULL, "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, @@ -1426,7 +1393,8 @@ static void node_composit_buts_viewlayers(uiLayout *layout, bContext *C, Pointer bNode *node = ptr->data; uiLayout *col, *row; - uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL); + uiTemplateID( + layout, C, ptr, "scene", NULL, NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL); if (!node->id) { return; @@ -1548,7 +1516,8 @@ static void node_composit_buts_defocus(uiLayout *layout, bContext *C, PointerRNA col = uiLayoutColumn(layout, false); uiItemR(col, ptr, "use_preview", DEFAULT_FLAGS, NULL, ICON_NONE); - uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL); + uiTemplateID( + layout, C, ptr, "scene", NULL, NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL); col = uiLayoutColumn(layout, false); uiItemR(col, ptr, "use_zbuffer", DEFAULT_FLAGS, NULL, ICON_NONE); @@ -2163,8 +2132,17 @@ static void node_composit_buts_ycc(uiLayout *layout, bContext *UNUSED(C), Pointe static void node_composit_buts_movieclip(uiLayout *layout, bContext *C, PointerRNA *ptr) { - uiTemplateID( - layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL); + uiTemplateID(layout, + C, + ptr, + "clip", + NULL, + NULL, + "CLIP_OT_open", + NULL, + UI_TEMPLATE_ID_FILTER_ALL, + false, + NULL); } static void node_composit_buts_movieclip_ex(uiLayout *layout, bContext *C, PointerRNA *ptr) @@ -2172,8 +2150,17 @@ static void node_composit_buts_movieclip_ex(uiLayout *layout, bContext *C, Point bNode *node = ptr->data; PointerRNA clipptr; - uiTemplateID( - layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL); + uiTemplateID(layout, + C, + ptr, + "clip", + NULL, + NULL, + "CLIP_OT_open", + NULL, + UI_TEMPLATE_ID_FILTER_ALL, + false, + NULL); if (!node->id) { return; @@ -2188,8 +2175,17 @@ static void node_composit_buts_stabilize2d(uiLayout *layout, bContext *C, Pointe { bNode *node = ptr->data; - uiTemplateID( - layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL); + uiTemplateID(layout, + C, + ptr, + "clip", + NULL, + NULL, + "CLIP_OT_open", + NULL, + UI_TEMPLATE_ID_FILTER_ALL, + false, + NULL); if (!node->id) { return; @@ -2214,8 +2210,17 @@ static void node_composit_buts_moviedistortion(uiLayout *layout, bContext *C, Po { bNode *node = ptr->data; - uiTemplateID( - layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL); + uiTemplateID(layout, + C, + ptr, + "clip", + NULL, + NULL, + "CLIP_OT_open", + NULL, + UI_TEMPLATE_ID_FILTER_ALL, + false, + NULL); if (!node->id) { return; @@ -2538,7 +2543,8 @@ static void node_composit_buts_mask(uiLayout *layout, bContext *C, PointerRNA *p { bNode *node = ptr->data; - uiTemplateID(layout, C, ptr, "mask", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL); + uiTemplateID( + layout, C, ptr, "mask", NULL, NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL); uiItemR(layout, ptr, "use_feather", DEFAULT_FLAGS, NULL, ICON_NONE); uiItemR(layout, ptr, "size_source", DEFAULT_FLAGS, "", ICON_NONE); @@ -2559,7 +2565,8 @@ static void node_composit_buts_keyingscreen(uiLayout *layout, bContext *C, Point { bNode *node = ptr->data; - uiTemplateID(layout, C, ptr, "clip", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL); + uiTemplateID( + layout, C, ptr, "clip", NULL, NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL); if (node->id) { MovieClip *clip = (MovieClip *)node->id; @@ -2595,8 +2602,17 @@ static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRN { bNode *node = ptr->data; - uiTemplateID( - layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL); + uiTemplateID(layout, + C, + ptr, + "clip", + NULL, + NULL, + "CLIP_OT_open", + NULL, + UI_TEMPLATE_ID_FILTER_ALL, + false, + NULL); if (node->id) { MovieClip *clip = (MovieClip *)node->id; @@ -2636,8 +2652,17 @@ static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, P bNode *node = ptr->data; NodePlaneTrackDeformData *data = node->storage; - uiTemplateID( - layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL); + uiTemplateID(layout, + C, + ptr, + "clip", + NULL, + NULL, + "CLIP_OT_open", + NULL, + UI_TEMPLATE_ID_FILTER_ALL, + false, + NULL); if (node->id) { MovieClip *clip = (MovieClip *)node->id; @@ -3072,6 +3097,7 @@ static void node_texture_buts_image(uiLayout *layout, bContext *C, PointerRNA *p ptr, "image", "IMAGE_OT_new", + NULL, "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, @@ -3149,6 +3175,15 @@ static void node_geometry_buts_boolean_math(uiLayout *layout, bContext *UNUSED(C uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE); } +static void node_geometry_buts_attribute_compare(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ + uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(layout, ptr, "input_type_a", DEFAULT_FLAGS, IFACE_("Type A"), ICON_NONE); + uiItemR(layout, ptr, "input_type_b", DEFAULT_FLAGS, IFACE_("Type B"), ICON_NONE); +} + static void node_geometry_buts_subdivision_surface(uiLayout *layout, bContext *UNUSED(C), PointerRNA *UNUSED(ptr)) @@ -3182,6 +3217,49 @@ static void node_geometry_buts_attribute_math(uiLayout *layout, uiItemR(layout, ptr, "input_type_b", DEFAULT_FLAGS, IFACE_("Type B"), ICON_NONE); } +static void node_geometry_buts_point_instance(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ + uiItemR(layout, ptr, "instance_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); + if (RNA_enum_get(ptr, "instance_type") == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION) { + uiItemR(layout, ptr, "use_whole_collection", DEFAULT_FLAGS, NULL, ICON_NONE); + } +} + +static void node_geometry_buts_attribute_fill(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ + uiItemR(layout, ptr, "data_type", DEFAULT_FLAGS, "", ICON_NONE); + // uiItemR(layout, ptr, "domain", DEFAULT_FLAGS, "", ICON_NONE); +} + +static void node_geometry_buts_attribute_mix(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ + uiItemR(layout, ptr, "blend_type", DEFAULT_FLAGS, "", ICON_NONE); + uiLayout *col = uiLayoutColumn(layout, false); + uiItemR(col, ptr, "input_type_factor", DEFAULT_FLAGS, IFACE_("Factor"), ICON_NONE); + uiItemR(col, ptr, "input_type_a", DEFAULT_FLAGS, IFACE_("A"), ICON_NONE); + uiItemR(col, ptr, "input_type_b", DEFAULT_FLAGS, IFACE_("B"), ICON_NONE); +} + +static void node_geometry_buts_attribute_point_distribute(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ + uiItemR(layout, ptr, "distribute_method", DEFAULT_FLAGS, "", ICON_NONE); +} + +static void node_geometry_buts_attribute_color_ramp(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ + uiTemplateColorRamp(layout, ptr, "color_ramp", 0); +} + static void node_geometry_set_butfunc(bNodeType *ntype) { switch (ntype->type) { @@ -3194,12 +3272,30 @@ static void node_geometry_set_butfunc(bNodeType *ntype) case GEO_NODE_TRIANGULATE: ntype->draw_buttons = node_geometry_buts_triangulate; break; - case GEO_NODE_RANDOM_ATTRIBUTE: + case GEO_NODE_ATTRIBUTE_RANDOMIZE: ntype->draw_buttons = node_geometry_buts_random_attribute; break; case GEO_NODE_ATTRIBUTE_MATH: ntype->draw_buttons = node_geometry_buts_attribute_math; break; + case GEO_NODE_ATTRIBUTE_COMPARE: + ntype->draw_buttons = node_geometry_buts_attribute_compare; + break; + case GEO_NODE_POINT_INSTANCE: + ntype->draw_buttons = node_geometry_buts_point_instance; + break; + case GEO_NODE_ATTRIBUTE_FILL: + ntype->draw_buttons = node_geometry_buts_attribute_fill; + break; + case GEO_NODE_ATTRIBUTE_MIX: + ntype->draw_buttons = node_geometry_buts_attribute_mix; + break; + case GEO_NODE_POINT_DISTRIBUTE: + ntype->draw_buttons = node_geometry_buts_attribute_point_distribute; + break; + case GEO_NODE_ATTRIBUTE_COLOR_RAMP: + ntype->draw_buttons = node_geometry_buts_attribute_color_ramp; + break; } } @@ -3222,6 +3318,12 @@ static void node_function_buts_switch(uiLayout *layout, bContext *UNUSED(C), Poi uiItemR(layout, ptr, "data_type", DEFAULT_FLAGS, "", ICON_NONE); } +static void node_function_buts_input_vector(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiLayout *col = uiLayoutColumn(layout, true); + uiItemR(col, ptr, "vector", UI_ITEM_R_EXPAND, "", ICON_NONE); +} + static void node_function_set_butfunc(bNodeType *ntype) { switch (ntype->type) { @@ -3234,6 +3336,9 @@ static void node_function_set_butfunc(bNodeType *ntype) case FN_NODE_SWITCH: ntype->draw_buttons = node_function_buts_switch; break; + case FN_NODE_INPUT_VECTOR: + ntype->draw_buttons = node_function_buts_input_vector; + break; } } @@ -3389,6 +3494,7 @@ static const float std_node_socket_colors[][4] = { {0.93, 0.62, 0.36, 1.0}, /* SOCK_OBJECT */ {0.89, 0.76, 0.43, 1.0}, /* SOCK_IMAGE */ {0.00, 0.84, 0.64, 1.0}, /* SOCK_GEOMETRY */ + {0.96, 0.96, 0.96, 1.0}, /* SOCK_COLLECTION */ }; /* common color callbacks for standard types */ @@ -3512,6 +3618,10 @@ static void std_node_socket_draw( uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, text, 0); break; } + case SOCK_COLLECTION: { + uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, text, 0); + break; + } default: node_socket_button_label(C, layout, ptr, node_ptr, text); break; diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c index fc7fa3a6caa..d3fec7257f5 100644 --- a/source/blender/editors/space_node/node_draw.c +++ b/source/blender/editors/space_node/node_draw.c @@ -344,8 +344,6 @@ void node_from_view(struct bNode *node, float x, float y, float *rx, float *ry) /* based on settings in node, sets drawing rect info. each redraw! */ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node) { - uiLayout *layout, *row; - PointerRNA nodeptr; RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr); @@ -374,15 +372,15 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node) PointerRNA sockptr; RNA_pointer_create(&ntree->id, &RNA_NodeSocket, nsock, &sockptr); - layout = UI_block_layout(node->block, - UI_LAYOUT_VERTICAL, - UI_LAYOUT_PANEL, - locx + NODE_DYS, - dy, - NODE_WIDTH(node) - NODE_DY, - NODE_DY, - 0, - UI_style_get_dpi()); + uiLayout *layout = UI_block_layout(node->block, + UI_LAYOUT_VERTICAL, + UI_LAYOUT_PANEL, + locx + NODE_DYS, + dy, + NODE_WIDTH(node) - NODE_DY, + NODE_DY, + 0, + UI_style_get_dpi()); if (node->flag & NODE_MUTED) { uiLayoutSetActive(layout, false); @@ -393,7 +391,7 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node) uiLayoutSetContextPointer(layout, "socket", &sockptr); /* align output buttons to the right */ - row = uiLayoutRow(layout, 1); + uiLayout *row = uiLayoutRow(layout, true); uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_RIGHT); const char *socket_label = nodeSocketLabel(nsock); nsock->typeinfo->draw((bContext *)C, row, &sockptr, &nodeptr, IFACE_(socket_label)); @@ -469,15 +467,15 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node) node->butr.ymin = 0; node->butr.ymax = 0; - layout = UI_block_layout(node->block, - UI_LAYOUT_VERTICAL, - UI_LAYOUT_PANEL, - locx + NODE_DYS, - dy, - node->butr.xmax, - 0, - 0, - UI_style_get_dpi()); + uiLayout *layout = UI_block_layout(node->block, + UI_LAYOUT_VERTICAL, + UI_LAYOUT_PANEL, + locx + NODE_DYS, + dy, + node->butr.xmax, + 0, + 0, + UI_style_get_dpi()); if (node->flag & NODE_MUTED) { uiLayoutSetActive(layout, false); @@ -502,15 +500,15 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node) PointerRNA sockptr; RNA_pointer_create(&ntree->id, &RNA_NodeSocket, nsock, &sockptr); - layout = UI_block_layout(node->block, - UI_LAYOUT_VERTICAL, - UI_LAYOUT_PANEL, - locx + NODE_DYS, - dy, - NODE_WIDTH(node) - NODE_DY, - NODE_DY, - 0, - UI_style_get_dpi()); + uiLayout *layout = UI_block_layout(node->block, + UI_LAYOUT_VERTICAL, + UI_LAYOUT_PANEL, + locx + NODE_DYS, + dy, + NODE_WIDTH(node) - NODE_DY, + NODE_DY, + 0, + UI_style_get_dpi()); if (node->flag & NODE_MUTED) { uiLayoutSetActive(layout, false); @@ -520,7 +518,7 @@ static void node_update_basis(const bContext *C, bNodeTree *ntree, bNode *node) uiLayoutSetContextPointer(layout, "node", &nodeptr); uiLayoutSetContextPointer(layout, "socket", &sockptr); - row = uiLayoutRow(layout, 1); + uiLayout *row = uiLayoutRow(layout, true); const char *socket_label = nodeSocketLabel(nsock); nsock->typeinfo->draw((bContext *)C, row, &sockptr, &nodeptr, IFACE_(socket_label)); @@ -771,7 +769,6 @@ void node_socket_color_get( bContext *C, bNodeTree *ntree, PointerRNA *node_ptr, bNodeSocket *sock, float r_color[4]) { PointerRNA ptr; - BLI_assert(RNA_struct_is_a(node_ptr->type, &RNA_Node)); RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr); @@ -1623,7 +1620,6 @@ void node_draw_nodetree(const bContext *C, } bNodeInstanceKey key = BKE_node_instance_key(parent_key, ntree, node); - node->nr = a; /* index of node in list, used for exec event code */ node_draw(C, region, snode, ntree, node, key); } @@ -1646,7 +1642,6 @@ void node_draw_nodetree(const bContext *C, } bNodeInstanceKey key = BKE_node_instance_key(parent_key, ntree, node); - node->nr = a; /* index of node in list, used for exec event code */ node_draw(C, region, snode, ntree, node, key); } } diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index 039ddad71ef..e6f11f3eb83 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -100,9 +100,7 @@ typedef struct CompoJob { static void compo_tag_output_nodes(bNodeTree *nodetree, int recalc_flags) { - bNode *node; - - for (node = nodetree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &nodetree->nodes) { if (node->type == CMP_NODE_COMPOSITE) { if (recalc_flags & COM_RECALC_COMPOSITE) { node->flag |= NODE_DO_OUTPUT_RECALC; @@ -124,14 +122,12 @@ static void compo_tag_output_nodes(bNodeTree *nodetree, int recalc_flags) static int compo_get_recalc_flags(const bContext *C) { wmWindowManager *wm = CTX_wm_manager(C); - wmWindow *win; int recalc_flags = 0; - for (win = wm->windows.first; win; win = win->next) { + LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { const bScreen *screen = WM_window_get_active_screen(win); - ScrArea *area; - for (area = screen->areabase.first; area; area = area->next) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { if (area->spacetype == SPACE_IMAGE) { SpaceImage *sima = area->spacedata.first; if (sima->image) { @@ -247,7 +243,6 @@ static void compo_startjob(void *cjv, CompoJob *cj = cjv; bNodeTree *ntree = cj->localtree; Scene *scene = cj->scene; - SceneRenderView *srv; if (scene->use_nodes == false) { return; @@ -280,7 +275,7 @@ static void compo_startjob(void *cjv, ""); } else { - for (srv = scene->r.views.first; srv; srv = srv->next) { + LISTBASE_FOREACH (SceneRenderView *, srv, &scene->r.views) { if (BKE_scene_multiview_is_render_view_active(&scene->r, srv) == false) { continue; } @@ -309,8 +304,6 @@ static void compo_startjob(void *cjv, */ void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene *scene_owner) { - wmJob *wm_job; - CompoJob *cj; Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); @@ -327,13 +320,13 @@ void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene BKE_image_backup_render( scene, BKE_image_ensure_viewer(bmain, IMA_TYPE_R_RESULT, "Render Result"), false); - wm_job = WM_jobs_get(CTX_wm_manager(C), - CTX_wm_window(C), - scene_owner, - "Compositing", - WM_JOB_EXCL_RENDER | WM_JOB_PROGRESS, - WM_JOB_TYPE_COMPOSITE); - cj = MEM_callocN(sizeof(CompoJob), "compo job"); + wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), + CTX_wm_window(C), + scene_owner, + "Compositing", + WM_JOB_EXCL_RENDER | WM_JOB_PROGRESS, + WM_JOB_TYPE_COMPOSITE); + CompoJob *cj = MEM_callocN(sizeof(CompoJob), "compo job"); /* customdata for preview thread */ cj->bmain = bmain; @@ -524,9 +517,6 @@ void ED_node_shader_default(const bContext *C, ID *id) /* called from shading buttons or header */ void ED_node_composit_default(const bContext *C, struct Scene *sce) { - bNode *in, *out; - bNodeSocket *fromsock, *tosock; - /* but lets check it anyway */ if (sce->nodetree) { if (G.debug & G_DEBUG) { @@ -541,18 +531,18 @@ void ED_node_composit_default(const bContext *C, struct Scene *sce) sce->nodetree->edit_quality = NTREE_QUALITY_HIGH; sce->nodetree->render_quality = NTREE_QUALITY_HIGH; - out = nodeAddStaticNode(C, sce->nodetree, CMP_NODE_COMPOSITE); + bNode *out = nodeAddStaticNode(C, sce->nodetree, CMP_NODE_COMPOSITE); out->locx = 300.0f; out->locy = 400.0f; - in = nodeAddStaticNode(C, sce->nodetree, CMP_NODE_R_LAYERS); + bNode *in = nodeAddStaticNode(C, sce->nodetree, CMP_NODE_R_LAYERS); in->locx = 10.0f; in->locy = 400.0f; nodeSetActive(sce->nodetree, in); /* links from color to color */ - fromsock = in->outputs.first; - tosock = out->inputs.first; + bNodeSocket *fromsock = in->outputs.first; + bNodeSocket *tosock = out->inputs.first; nodeAddLink(sce->nodetree, in, fromsock, out, tosock); ntreeUpdateTree(CTX_data_main(C), sce->nodetree); @@ -562,9 +552,6 @@ void ED_node_composit_default(const bContext *C, struct Scene *sce) /* called from shading buttons or header */ void ED_node_texture_default(const bContext *C, Tex *tex) { - bNode *in, *out; - bNodeSocket *fromsock, *tosock; - /* but lets check it anyway */ if (tex->nodetree) { if (G.debug & G_DEBUG) { @@ -575,17 +562,17 @@ void ED_node_texture_default(const bContext *C, Tex *tex) tex->nodetree = ntreeAddTree(NULL, "Texture Nodetree", ntreeType_Texture->idname); - out = nodeAddStaticNode(C, tex->nodetree, TEX_NODE_OUTPUT); + bNode *out = nodeAddStaticNode(C, tex->nodetree, TEX_NODE_OUTPUT); out->locx = 300.0f; out->locy = 300.0f; - in = nodeAddStaticNode(C, tex->nodetree, TEX_NODE_CHECKER); + bNode *in = nodeAddStaticNode(C, tex->nodetree, TEX_NODE_CHECKER); in->locx = 10.0f; in->locy = 300.0f; nodeSetActive(tex->nodetree, in); - fromsock = in->outputs.first; - tosock = out->inputs.first; + bNodeSocket *fromsock = in->outputs.first; + bNodeSocket *tosock = out->inputs.first; nodeAddLink(tex->nodetree, in, fromsock, out, tosock); ntreeUpdateTree(CTX_data_main(C), tex->nodetree); @@ -634,15 +621,13 @@ void snode_set_context(const bContext *C) void snode_update(SpaceNode *snode, bNode *node) { - bNodeTreePath *path; - /* XXX this only updates nodes in the current node space tree path. * The function supposedly should update any potential group node linking to changed tree, * this really requires a working depsgraph ... */ /* update all edited group nodes */ - path = snode->treepath.last; + bNodeTreePath *path = snode->treepath.last; if (path) { bNodeTree *ngroup = path->nodetree; for (path = path->prev; path; path = path->prev) { @@ -671,10 +656,9 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node, bool *r_acti /* generic node group output: set node as active output */ if (node->type == NODE_GROUP_OUTPUT) { - bNode *tnode; - for (tnode = ntree->nodes.first; tnode; tnode = tnode->next) { - if (tnode->type == NODE_GROUP_OUTPUT) { - tnode->flag &= ~NODE_DO_OUTPUT; + LISTBASE_FOREACH (bNode *, node_iter, &ntree->nodes) { + if (node_iter->type == NODE_GROUP_OUTPUT) { + node_iter->flag &= ~NODE_DO_OUTPUT; } } @@ -696,11 +680,9 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node, bool *r_acti SH_NODE_OUTPUT_WORLD, SH_NODE_OUTPUT_LIGHT, SH_NODE_OUTPUT_LINESTYLE)) { - bNode *tnode; - - for (tnode = ntree->nodes.first; tnode; tnode = tnode->next) { - if (tnode->type == node->type) { - tnode->flag &= ~NODE_DO_OUTPUT; + LISTBASE_FOREACH (bNode *, node_iter, &ntree->nodes) { + if (node_iter->type == node->type) { + node_iter->flag &= ~NODE_DO_OUTPUT; } } @@ -715,16 +697,13 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node, bool *r_acti /* if active texture changed, free glsl materials */ if ((node->flag & NODE_ACTIVE_TEXTURE) && !was_active_texture) { - Material *ma; - World *wo; - - for (ma = bmain->materials.first; ma; ma = ma->id.next) { + LISTBASE_FOREACH (Material *, ma, &bmain->materials) { if (ma->nodetree && ma->use_nodes && ntreeHasTree(ma->nodetree, ntree)) { GPU_material_free(&ma->gpumaterial); } } - for (wo = bmain->worlds.first; wo; wo = wo->id.next) { + LISTBASE_FOREACH (World *, wo, &bmain->materials) { if (wo->nodetree && wo->use_nodes && ntreeHasTree(wo->nodetree, ntree)) { GPU_material_free(&wo->gpumaterial); } @@ -742,11 +721,9 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node, bool *r_acti else if (ntree->type == NTREE_COMPOSIT) { /* make active viewer, currently only 1 supported... */ if (ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) { - bNode *tnode; - - for (tnode = ntree->nodes.first; tnode; tnode = tnode->next) { - if (ELEM(tnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) { - tnode->flag &= ~NODE_DO_OUTPUT; + LISTBASE_FOREACH (bNode *, node_iter, &ntree->nodes) { + if (ELEM(node_iter->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) { + node_iter->flag &= ~NODE_DO_OUTPUT; } } @@ -760,11 +737,9 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node, bool *r_acti } else if (node->type == CMP_NODE_COMPOSITE) { if (was_output == 0) { - bNode *tnode; - - for (tnode = ntree->nodes.first; tnode; tnode = tnode->next) { - if (tnode->type == CMP_NODE_COMPOSITE) { - tnode->flag &= ~NODE_DO_OUTPUT; + LISTBASE_FOREACH (bNode *, node_iter, &ntree->nodes) { + if (node_iter->type == CMP_NODE_COMPOSITE) { + node_iter->flag &= ~NODE_DO_OUTPUT; } } @@ -879,14 +854,12 @@ static void edit_node_properties_get( /* is rct in visible part of node? */ static bNode *visible_node(SpaceNode *snode, const rctf *rct) { - bNode *node; - - for (node = snode->edittree->nodes.last; node; node = node->prev) { + LISTBASE_FOREACH_BACKWARD (bNode *, node, &snode->edittree->nodes) { if (BLI_rctf_isect(&node->totr, rct, NULL)) { - break; + return node; } } - return node; + return NULL; } /* ********************** size widget operator ******************** */ @@ -952,23 +925,19 @@ static int node_resize_modal(bContext *C, wmOperator *op, const wmEvent *event) ARegion *region = CTX_wm_region(C); bNode *node = nodeGetActive(snode->edittree); NodeSizeWidget *nsw = op->customdata; - float mx, my, dx, dy; switch (event->type) { - case MOUSEMOVE: - + case MOUSEMOVE: { + float mx, my; UI_view2d_region_to_view(®ion->v2d, event->mval[0], event->mval[1], &mx, &my); - dx = (mx - nsw->mxstart) / UI_DPI_FAC; - dy = (my - nsw->mystart) / UI_DPI_FAC; + float dx = (mx - nsw->mxstart) / UI_DPI_FAC; + float dy = (my - nsw->mystart) / UI_DPI_FAC; if (node) { - float *pwidth; - float oldwidth, widthmin, widthmax; - - pwidth = &node->width; - oldwidth = nsw->oldwidth; - widthmin = node->typeinfo->minwidth; - widthmax = node->typeinfo->maxwidth; + float *pwidth = &node->width; + float oldwidth = nsw->oldwidth; + float widthmin = node->typeinfo->minwidth; + float widthmax = node->typeinfo->maxwidth; { if (nsw->directions & NODE_RESIZE_RIGHT) { @@ -1026,23 +995,24 @@ static int node_resize_modal(bContext *C, wmOperator *op, const wmEvent *event) ED_region_tag_redraw(region); break; - + } case LEFTMOUSE: case MIDDLEMOUSE: - case RIGHTMOUSE: + case RIGHTMOUSE: { if (event->val == KM_RELEASE) { node_resize_exit(C, op, false); ED_node_post_apply_transform(C, snode->edittree); return OPERATOR_FINISHED; } - else if (event->val == KM_PRESS) { + if (event->val == KM_PRESS) { node_resize_exit(C, op, true); ED_region_tag_redraw(region); return OPERATOR_CANCELLED; } break; + } } return OPERATOR_RUNNING_MODAL; @@ -1095,14 +1065,12 @@ void NODE_OT_resize(wmOperatorType *ot) bool node_has_hidden_sockets(bNode *node) { - bNodeSocket *sock; - - for (sock = node->inputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { if (sock->flag & SOCK_HIDDEN) { return true; } } - for (sock = node->outputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { if (sock->flag & SOCK_HIDDEN) { return true; } @@ -1112,24 +1080,22 @@ bool node_has_hidden_sockets(bNode *node) void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set) { - bNodeSocket *sock; - if (set == 0) { - for (sock = node->inputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { sock->flag &= ~SOCK_HIDDEN; } - for (sock = node->outputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { sock->flag &= ~SOCK_HIDDEN; } } else { /* hide unused sockets */ - for (sock = node->inputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { if (sock->link == NULL) { sock->flag |= SOCK_HIDDEN; } } - for (sock = node->outputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { if (nodeCountSocketLinks(snode->edittree, sock) == 0) { sock->flag |= SOCK_HIDDEN; } @@ -1142,16 +1108,13 @@ void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set) int node_find_indicated_socket( SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, float cursor[2], int in_out) { - bNode *node; - bNodeSocket *sock; rctf rect; *nodep = NULL; *sockp = NULL; /* check if we click in a socket */ - for (node = snode->edittree->nodes.first; node; node = node->next) { - + LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) { BLI_rctf_init_pt_radius(&rect, cursor, NODE_SOCKSIZE + 4); if (!(node->flag & NODE_HIDDEN)) { @@ -1167,7 +1130,7 @@ int node_find_indicated_socket( } if (in_out & SOCK_IN) { - for (sock = node->inputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { if (!nodeSocketIsHidden(sock)) { if (BLI_rctf_isect_pt(&rect, sock->locx, sock->locy)) { if (node == visible_node(snode, &rect)) { @@ -1180,7 +1143,7 @@ int node_find_indicated_socket( } } if (in_out & SOCK_OUT) { - for (sock = node->outputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { if (!nodeSocketIsHidden(sock)) { if (BLI_rctf_isect_pt(&rect, sock->locx, sock->locy)) { if (node == visible_node(snode, &rect)) { @@ -1226,17 +1189,15 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) Main *bmain = CTX_data_main(C); SpaceNode *snode = CTX_wm_space_node(C); bNodeTree *ntree = snode->edittree; - bNode *node, *newnode, *lastnode; - bNodeLink *link, *newlink, *lastlink; const bool keep_inputs = RNA_boolean_get(op->ptr, "keep_inputs"); bool do_tag_update = false; ED_preview_kill_jobs(CTX_wm_manager(C), bmain); - lastnode = ntree->nodes.last; - for (node = ntree->nodes.first; node; node = node->next) { + bNode *lastnode = ntree->nodes.last; + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->flag & SELECT) { - newnode = BKE_node_copy_store_new_pointers(ntree, node, LIB_ID_COPY_DEFAULT); + BKE_node_copy_store_new_pointers(ntree, node, LIB_ID_COPY_DEFAULT); /* to ensure redraws or rerenders happen */ ED_node_tag_update_id(snode->id); @@ -1251,14 +1212,14 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) /* copy links between selected nodes * NB: this depends on correct node->new_node and sock->new_sock pointers from above copy! */ - lastlink = ntree->links.last; - for (link = ntree->links.first; link; link = link->next) { + bNodeLink *lastlink = ntree->links.last; + LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { /* This creates new links between copied nodes. * If keep_inputs is set, also copies input links from unselected (when fromnode==NULL)! */ if (link->tonode && (link->tonode->flag & NODE_SELECT) && (keep_inputs || (link->fromnode && (link->fromnode->flag & NODE_SELECT)))) { - newlink = MEM_callocN(sizeof(bNodeLink), "bNodeLink"); + bNodeLink *newlink = MEM_callocN(sizeof(bNodeLink), "bNodeLink"); newlink->flag = link->flag; newlink->tonode = link->tonode->new_node; newlink->tosock = link->tosock->new_sock; @@ -1282,11 +1243,11 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) } /* clear flags for recursive depth-first iteration */ - for (node = ntree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { node->flag &= ~NODE_TEST; } /* reparent copied nodes */ - for (node = ntree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if ((node->flag & SELECT) && !(node->flag & NODE_TEST)) { node_duplicate_reparent_recursive(node); } @@ -1298,10 +1259,10 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) } /* deselect old nodes, select the copies instead */ - for (node = ntree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->flag & SELECT) { /* has been set during copy above */ - newnode = node->new_node; + bNode *newnode = node->new_node; nodeSetSelected(node, false); node->flag &= ~(NODE_ACTIVE | NODE_ACTIVE_TEXTURE); @@ -1389,17 +1350,16 @@ static int node_read_viewlayers_exec(bContext *C, wmOperator *UNUSED(op)) { Main *bmain = CTX_data_main(C); SpaceNode *snode = CTX_wm_space_node(C); - Scene *curscene = CTX_data_scene(C), *scene; - bNode *node; + Scene *curscene = CTX_data_scene(C); ED_preview_kill_jobs(CTX_wm_manager(C), bmain); /* first tag scenes unread */ - for (scene = bmain->scenes.first; scene; scene = scene->id.next) { + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { scene->id.tag |= LIB_TAG_DOIT; } - for (node = snode->edittree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) { if (node->type == CMP_NODE_R_LAYERS) { ID *id = node->id; if (id->tag & LIB_TAG_DOIT) { @@ -1434,13 +1394,14 @@ void NODE_OT_read_viewlayers(wmOperatorType *ot) int node_render_changed_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *sce = CTX_data_scene(C); - bNode *node; /* This is actually a test whether scene is used by the compositor or not. * All the nodes are using same render result, so there is no need to do * anything smart about check how exactly scene is used. */ - for (node = sce->nodetree->nodes.first; node; node = node->next) { - if (node->id == (ID *)sce) { + bNode *node = NULL; + LISTBASE_FOREACH (bNode *, node_iter, &sce->nodetree->nodes) { + if (node_iter->id == (ID *)sce) { + node = node_iter; break; } } @@ -1486,14 +1447,14 @@ void NODE_OT_render_changed(wmOperatorType *ot) static void node_flag_toggle_exec(SpaceNode *snode, int toggle_flag) { - bNode *node; int tot_eq = 0, tot_neq = 0; /* Toggles the flag on all selected nodes. * If the flag is set on all nodes it is unset. * If the flag is not set on all nodes, it is set. */ - for (node = snode->edittree->nodes.first; node; node = node->next) { + + LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) { if (node->flag & SELECT) { if (toggle_flag == NODE_PREVIEW && (node->typeinfo->flag & NODE_PREVIEW) == 0) { @@ -1512,7 +1473,7 @@ static void node_flag_toggle_exec(SpaceNode *snode, int toggle_flag) } } } - for (node = snode->edittree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) { if (node->flag & SELECT) { if (toggle_flag == NODE_PREVIEW && (node->typeinfo->flag & NODE_PREVIEW) == 0) { @@ -1631,8 +1592,6 @@ void NODE_OT_options_toggle(wmOperatorType *ot) static int node_socket_toggle_exec(bContext *C, wmOperator *UNUSED(op)) { SpaceNode *snode = CTX_wm_space_node(C); - bNode *node; - int hidden; /* sanity checking (poll callback checks this already) */ if ((snode == NULL) || (snode->edittree == NULL)) { @@ -1642,17 +1601,17 @@ static int node_socket_toggle_exec(bContext *C, wmOperator *UNUSED(op)) ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); /* Toggle for all selected nodes */ - hidden = 0; - for (node = snode->edittree->nodes.first; node; node = node->next) { + bool hidden = false; + LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) { if (node->flag & SELECT) { if (node_has_hidden_sockets(node)) { - hidden = 1; + hidden = true; break; } } } - for (node = snode->edittree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) { if (node->flag & SELECT) { node_set_hidden_sockets(snode, node, !hidden); } @@ -1686,12 +1645,11 @@ static int node_mute_exec(bContext *C, wmOperator *UNUSED(op)) { Main *bmain = CTX_data_main(C); SpaceNode *snode = CTX_wm_space_node(C); - bNode *node; bool do_tag_update = false; ED_preview_kill_jobs(CTX_wm_manager(C), bmain); - for (node = snode->edittree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) { /* Only allow muting of nodes having a mute func! */ if ((node->flag & SELECT) && node->typeinfo->update_internal_links) { node->flag ^= NODE_MUTED; @@ -1731,13 +1689,11 @@ static int node_delete_exec(bContext *C, wmOperator *UNUSED(op)) { Main *bmain = CTX_data_main(C); SpaceNode *snode = CTX_wm_space_node(C); - bNode *node, *next; bool do_tag_update = false; ED_preview_kill_jobs(CTX_wm_manager(C), bmain); - for (node = snode->edittree->nodes.first; node; node = next) { - next = node->next; + LISTBASE_FOREACH_MUTABLE (bNode *, node, &snode->edittree->nodes) { if (node->flag & SELECT) { do_tag_update |= (do_tag_update || node_connected_to_output(bmain, snode->edittree, node)); nodeRemoveNode(bmain, snode->edittree, node, true); @@ -1787,10 +1743,8 @@ static bool node_switch_view_poll(bContext *C) static int node_switch_view_exec(bContext *C, wmOperator *UNUSED(op)) { SpaceNode *snode = CTX_wm_space_node(C); - bNode *node, *next; - for (node = snode->edittree->nodes.first; node; node = next) { - next = node->next; + LISTBASE_FOREACH_MUTABLE (bNode *, node, &snode->edittree->nodes) { if (node->flag & SELECT) { /* call the update function from the Switch View node */ node->update = NODE_UPDATE_OPERATOR; @@ -1825,12 +1779,10 @@ static int node_delete_reconnect_exec(bContext *C, wmOperator *UNUSED(op)) { Main *bmain = CTX_data_main(C); SpaceNode *snode = CTX_wm_space_node(C); - bNode *node, *next; ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); - for (node = snode->edittree->nodes.first; node; node = next) { - next = node->next; + LISTBASE_FOREACH_MUTABLE (bNode *, node, &snode->edittree->nodes) { if (node->flag & SELECT) { nodeInternalRelink(snode->edittree, node); nodeRemoveNode(bmain, snode->edittree, node, true); @@ -1963,9 +1915,6 @@ static int node_output_file_move_active_socket_exec(bContext *C, wmOperator *op) SpaceNode *snode = CTX_wm_space_node(C); PointerRNA ptr = CTX_data_pointer_get(C, "node"); bNode *node = NULL; - NodeImageMultiFile *nimf; - bNodeSocket *sock; - int direction; if (ptr.data) { node = ptr.data; @@ -1978,14 +1927,14 @@ static int node_output_file_move_active_socket_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - nimf = node->storage; + NodeImageMultiFile *nimf = node->storage; - sock = BLI_findlink(&node->inputs, nimf->active_input); + bNodeSocket *sock = BLI_findlink(&node->inputs, nimf->active_input); if (!sock) { return OPERATOR_CANCELLED; } - direction = RNA_enum_get(op->ptr, "direction"); + int direction = RNA_enum_get(op->ptr, "direction"); if (direction == 1) { bNodeSocket *before = sock->prev; @@ -2037,24 +1986,23 @@ static int node_copy_color_exec(bContext *C, wmOperator *UNUSED(op)) { SpaceNode *snode = CTX_wm_space_node(C); bNodeTree *ntree = snode->edittree; - bNode *node, *tnode; if (!ntree) { return OPERATOR_CANCELLED; } - node = nodeGetActive(ntree); + bNode *node = nodeGetActive(ntree); if (!node) { return OPERATOR_CANCELLED; } - for (tnode = ntree->nodes.first; tnode; tnode = tnode->next) { - if (tnode->flag & NODE_SELECT && tnode != node) { + LISTBASE_FOREACH (bNode *, node_iter, &ntree->nodes) { + if (node_iter->flag & NODE_SELECT && node_iter != node) { if (node->flag & NODE_CUSTOM_COLOR) { - tnode->flag |= NODE_CUSTOM_COLOR; - copy_v3_v3(tnode->color, node->color); + node_iter->flag |= NODE_CUSTOM_COLOR; + copy_v3_v3(node_iter->color, node->color); } else { - tnode->flag &= ~NODE_CUSTOM_COLOR; + node_iter->flag &= ~NODE_CUSTOM_COLOR; } } } @@ -2086,8 +2034,6 @@ static int node_clipboard_copy_exec(bContext *C, wmOperator *UNUSED(op)) { SpaceNode *snode = CTX_wm_space_node(C); bNodeTree *ntree = snode->edittree; - bNode *node; - bNodeLink *link, *newlink; ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); @@ -2095,7 +2041,7 @@ static int node_clipboard_copy_exec(bContext *C, wmOperator *UNUSED(op)) BKE_node_clipboard_clear(); BKE_node_clipboard_init(ntree); - for (node = ntree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->flag & SELECT) { /* No ID refcounting, this node is virtual, * detached from any actual Blender data currently. */ @@ -2105,7 +2051,7 @@ static int node_clipboard_copy_exec(bContext *C, wmOperator *UNUSED(op)) } } - for (node = ntree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->flag & SELECT) { bNode *new_node = node->new_node; @@ -2126,11 +2072,11 @@ static int node_clipboard_copy_exec(bContext *C, wmOperator *UNUSED(op)) /* copy links between selected nodes * NB: this depends on correct node->new_node and sock->new_sock pointers from above copy! */ - for (link = ntree->links.first; link; link = link->next) { + LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { /* This creates new links between copied nodes. */ if (link->tonode && (link->tonode->flag & NODE_SELECT) && link->fromnode && (link->fromnode->flag & NODE_SELECT)) { - newlink = MEM_callocN(sizeof(bNodeLink), "bNodeLink"); + bNodeLink *newlink = MEM_callocN(sizeof(bNodeLink), "bNodeLink"); newlink->flag = link->flag; newlink->tonode = link->tonode->new_node; newlink->tosock = link->tosock->new_sock; @@ -2165,18 +2111,11 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) { SpaceNode *snode = CTX_wm_space_node(C); bNodeTree *ntree = snode->edittree; - const ListBase *clipboard_nodes_lb; - const ListBase *clipboard_links_lb; - bNode *node; - bNodeLink *link; - int num_nodes; - float center[2]; - bool is_clipboard_valid, all_nodes_valid; /* validate pointers in the clipboard */ - is_clipboard_valid = BKE_node_clipboard_validate(); - clipboard_nodes_lb = BKE_node_clipboard_get_nodes(); - clipboard_links_lb = BKE_node_clipboard_get_links(); + bool is_clipboard_valid = BKE_node_clipboard_validate(); + const ListBase *clipboard_nodes_lb = BKE_node_clipboard_get_nodes(); + const ListBase *clipboard_links_lb = BKE_node_clipboard_get_links(); if (BLI_listbase_is_empty(clipboard_nodes_lb)) { BKE_report(op->reports, RPT_ERROR, "Clipboard is empty"); @@ -2196,8 +2135,8 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) } /* make sure all clipboard nodes would be valid in the target tree */ - all_nodes_valid = true; - for (node = clipboard_nodes_lb->first; node; node = node->next) { + bool all_nodes_valid = true; + LISTBASE_FOREACH (bNode *, node, clipboard_nodes_lb) { if (!node->typeinfo->poll_instance || !node->typeinfo->poll_instance(node, ntree)) { all_nodes_valid = false; BKE_reportf(op->reports, @@ -2217,15 +2156,16 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) node_deselect_all(snode); /* calculate "barycenter" for placing on mouse cursor */ - zero_v2(center); - for (node = clipboard_nodes_lb->first, num_nodes = 0; node; node = node->next, num_nodes++) { + float center[2] = {0.0f, 0.0f}; + int num_nodes = 0; + LISTBASE_FOREACH_INDEX (bNode *, node, clipboard_nodes_lb, num_nodes) { center[0] += BLI_rctf_cent_x(&node->totr); center[1] += BLI_rctf_cent_y(&node->totr); } mul_v2_fl(center, 1.0 / num_nodes); /* copy nodes from clipboard */ - for (node = clipboard_nodes_lb->first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, clipboard_nodes_lb) { bNode *new_node = BKE_node_copy_store_new_pointers(ntree, node, LIB_ID_COPY_DEFAULT); /* pasted nodes are selected */ @@ -2233,14 +2173,14 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) } /* reparent copied nodes */ - for (node = clipboard_nodes_lb->first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, clipboard_nodes_lb) { bNode *new_node = node->new_node; if (new_node->parent) { new_node->parent = new_node->parent->new_node; } } - for (link = clipboard_links_lb->first; link; link = link->next) { + LISTBASE_FOREACH (bNodeLink *, link, clipboard_links_lb) { nodeAddLink(ntree, link->fromnode->new_node, link->fromsock->new_sock, @@ -2275,10 +2215,9 @@ void NODE_OT_clipboard_paste(wmOperatorType *ot) static bNodeSocket *ntree_get_active_interface_socket(ListBase *lb) { - bNodeSocket *sock; - for (sock = lb->first; sock; sock = sock->next) { - if (sock->flag & SELECT) { - return sock; + LISTBASE_FOREACH (bNodeSocket *, socket, lb) { + if (socket->flag & SELECT) { + return socket; } } return NULL; @@ -2289,12 +2228,12 @@ static int ntree_socket_add_exec(bContext *C, wmOperator *op) SpaceNode *snode = CTX_wm_space_node(C); bNodeTree *ntree = snode->edittree; int in_out = RNA_enum_get(op->ptr, "in_out"); - PointerRNA ntree_ptr; - bNodeSocket *sock, *tsock, *active_sock; - const char *default_name; + PointerRNA ntree_ptr; RNA_id_pointer_create((ID *)ntree, &ntree_ptr); + const char *default_name; + bNodeSocket *active_sock; if (in_out == SOCK_IN) { active_sock = ntree_get_active_interface_socket(&ntree->inputs); default_name = "Input"; @@ -2304,6 +2243,7 @@ static int ntree_socket_add_exec(bContext *C, wmOperator *op) default_name = "Output"; } + bNodeSocket *sock; if (active_sock) { /* insert a copy of the active socket right after it */ sock = ntreeInsertSocketInterface( @@ -2317,11 +2257,11 @@ static int ntree_socket_add_exec(bContext *C, wmOperator *op) } /* deactivate sockets (has to check both lists) */ - for (tsock = ntree->inputs.first; tsock; tsock = tsock->next) { - tsock->flag &= ~SELECT; + LISTBASE_FOREACH (bNodeSocket *, socket_iter, &ntree->inputs) { + socket_iter->flag &= ~SELECT; } - for (tsock = ntree->outputs.first; tsock; tsock = tsock->next) { - tsock->flag &= ~SELECT; + LISTBASE_FOREACH (bNodeSocket *, socket_iter, &ntree->outputs) { + socket_iter->flag &= ~SELECT; } /* make the new socket active */ sock->flag |= SELECT; @@ -2359,9 +2299,8 @@ static int ntree_socket_remove_exec(bContext *C, wmOperator *UNUSED(op)) { SpaceNode *snode = CTX_wm_space_node(C); bNodeTree *ntree = snode->edittree; - bNodeSocket *iosock, *active_sock; - iosock = ntree_get_active_interface_socket(&ntree->inputs); + bNodeSocket *iosock = ntree_get_active_interface_socket(&ntree->inputs); if (!iosock) { iosock = ntree_get_active_interface_socket(&ntree->outputs); } @@ -2370,7 +2309,7 @@ static int ntree_socket_remove_exec(bContext *C, wmOperator *UNUSED(op)) } /* preferably next socket becomes active, otherwise try previous socket */ - active_sock = (iosock->next ? iosock->next : iosock->prev); + bNodeSocket *active_sock = (iosock->next ? iosock->next : iosock->prev); ntreeRemoveSocketInterface(ntree, iosock); /* set active socket */ @@ -2416,11 +2355,9 @@ static int ntree_socket_move_exec(bContext *C, wmOperator *op) SpaceNode *snode = CTX_wm_space_node(C); bNodeTree *ntree = snode->edittree; int direction = RNA_enum_get(op->ptr, "direction"); - bNodeSocket *iosock; - ListBase *lb; - lb = &ntree->inputs; - iosock = ntree_get_active_interface_socket(lb); + ListBase *lb = &ntree->inputs; + bNodeSocket *iosock = ntree_get_active_interface_socket(lb); if (!iosock) { lb = &ntree->outputs; iosock = ntree_get_active_interface_socket(lb); @@ -2489,8 +2426,6 @@ static bool node_shader_script_update_poll(bContext *C) Scene *scene = CTX_data_scene(C); const RenderEngineType *type = RE_engines_find(scene->r.engine); SpaceNode *snode = CTX_wm_space_node(C); - bNode *node; - Text *text; /* test if we have a render engine that supports shaders scripts */ if (!(type && type->update_script_node)) { @@ -2498,7 +2433,7 @@ static bool node_shader_script_update_poll(bContext *C) } /* see if we have a shader script node in context */ - node = CTX_data_pointer_get_type(C, "node", &RNA_ShaderNodeScript).data; + bNode *node = CTX_data_pointer_get_type(C, "node", &RNA_ShaderNodeScript).data; if (!node && snode && snode->edittree) { node = nodeGetActive(snode->edittree); @@ -2513,7 +2448,7 @@ static bool node_shader_script_update_poll(bContext *C) } /* see if we have a text datablock in context */ - text = CTX_data_pointer_get_type(C, "edit_text", &RNA_Text).data; + Text *text = CTX_data_pointer_get_type(C, "edit_text", &RNA_Text).data; if (text) { return 1; } @@ -2530,12 +2465,11 @@ static bool node_shader_script_update_text_recursive(RenderEngine *engine, Text *text) { bool found = false; - bNode *node; ntree->done = true; /* update each script that is using this text datablock */ - for (node = ntree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->type == NODE_GROUP) { bNodeTree *ngroup = (bNodeTree *)node->id; if (ngroup && !ngroup->done) { @@ -2557,18 +2491,16 @@ static int node_shader_script_update_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); SpaceNode *snode = CTX_wm_space_node(C); PointerRNA nodeptr = CTX_data_pointer_get_type(C, "node", &RNA_ShaderNodeScript); - bNodeTree *ntree_base = NULL; - bNode *node = NULL; - RenderEngine *engine; - RenderEngineType *type; bool found = false; /* setup render engine */ - type = RE_engines_find(scene->r.engine); - engine = RE_engine_create(type); + RenderEngineType *type = RE_engines_find(scene->r.engine); + RenderEngine *engine = RE_engine_create(type); engine->reports = op->reports; /* get node */ + bNodeTree *ntree_base = NULL; + bNode *node = NULL; if (nodeptr.data) { ntree_base = (bNodeTree *)nodeptr.owner_id; node = nodeptr.data; @@ -2643,10 +2575,8 @@ static void viewer_border_corner_to_backdrop(SpaceNode *snode, float *fx, float *fy) { - float bufx, bufy; - - bufx = backdrop_width * snode->zoom; - bufy = backdrop_height * snode->zoom; + float bufx = backdrop_width * snode->zoom; + float bufy = backdrop_height * snode->zoom; *fx = (bufx > 0.0f ? ((float)x - 0.5f * region->winx - snode->xof) / bufx + 0.5f : 0.0f); *fy = (bufy > 0.0f ? ((float)y - 0.5f * region->winy - snode->yof) / bufy + 0.5f : 0.0f); @@ -2655,14 +2585,12 @@ static void viewer_border_corner_to_backdrop(SpaceNode *snode, static int viewer_border_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); - Image *ima; void *lock; - ImBuf *ibuf; ED_preview_kill_jobs(CTX_wm_manager(C), bmain); - ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node"); - ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock); + Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node"); + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock); if (ibuf) { ARegion *region = CTX_wm_region(C); diff --git a/source/blender/editors/space_node/node_view.c b/source/blender/editors/space_node/node_view.c index 3c861896d37..d2c88ed787c 100644 --- a/source/blender/editors/space_node/node_view.c +++ b/source/blender/editors/space_node/node_view.c @@ -283,7 +283,7 @@ void NODE_OT_backimage_move(wmOperatorType *ot) { /* identifiers */ ot->name = "Background Image Move"; - ot->description = "Move Node backdrop"; + ot->description = "Move node backdrop"; ot->idname = "NODE_OT_backimage_move"; /* api callbacks */ diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c index afc1a963f4f..ad7632377a3 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.c @@ -645,7 +645,7 @@ static bool node_ima_drop_poll(bContext *UNUSED(C), /* rule might not work? */ return (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_MOVIE)); } - return WM_drag_ID(drag, ID_IM) != NULL; + return WM_drag_get_local_ID(drag, ID_IM) != NULL; } static bool node_mask_drop_poll(bContext *UNUSED(C), @@ -653,19 +653,19 @@ static bool node_mask_drop_poll(bContext *UNUSED(C), const wmEvent *UNUSED(event), const char **UNUSED(r_tooltip)) { - return WM_drag_ID(drag, ID_MSK) != NULL; + return WM_drag_get_local_ID(drag, ID_MSK) != NULL; } static void node_id_drop_copy(wmDrag *drag, wmDropBox *drop) { - ID *id = WM_drag_ID(drag, 0); + ID *id = WM_drag_get_local_ID(drag, 0); RNA_string_set(drop->ptr, "name", id->name + 2); } static void node_id_path_drop_copy(wmDrag *drag, wmDropBox *drop) { - ID *id = WM_drag_ID(drag, 0); + ID *id = WM_drag_get_local_ID(drag, 0); if (id) { RNA_string_set(drop->ptr, "name", id->name + 2); diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt index 74f99540bee..e0262371559 100644 --- a/source/blender/editors/space_outliner/CMakeLists.txt +++ b/source/blender/editors/space_outliner/CMakeLists.txt @@ -34,6 +34,7 @@ set(INC set(SRC outliner_collections.c + outliner_context.c outliner_dragdrop.c outliner_draw.c outliner_edit.c @@ -46,12 +47,12 @@ set(SRC space_outliner.c tree/common.cc tree/tree_display.cc + tree/tree_display_data.cc tree/tree_display_libraries.cc - tree/tree_display_view_layer.cc - tree/tree_display_sequencer.cc tree/tree_display_orphaned.cc tree/tree_display_scenes.cc - tree/tree_display_data.cc + tree/tree_display_sequencer.cc + tree/tree_display_view_layer.cc tree/tree_element.cc tree/tree_element_anim_data.cc tree/tree_element_driver_base.cc diff --git a/source/blender/editors/space_outliner/outliner_context.c b/source/blender/editors/space_outliner/outliner_context.c new file mode 100644 index 00000000000..a314a640e42 --- /dev/null +++ b/source/blender/editors/space_outliner/outliner_context.c @@ -0,0 +1,73 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup spoutliner + */ + +#include "BLI_listbase.h" + +#include "BKE_context.h" + +#include "DNA_space_types.h" + +#include "RNA_access.h" + +#include "outliner_intern.h" + +static void outliner_context_selected_ids_recursive(const ListBase *subtree, + bContextDataResult *result) +{ + LISTBASE_FOREACH (const TreeElement *, te, subtree) { + const TreeStoreElem *tse = TREESTORE(te); + if ((tse->flag & TSE_SELECTED) && (ELEM(tse->type, 0, TSE_LAYER_COLLECTION))) { + CTX_data_id_list_add(result, tse->id); + } + outliner_context_selected_ids_recursive(&te->subtree, result); + } +} + +static void outliner_context_selected_ids(const SpaceOutliner *space_outliner, + bContextDataResult *result) +{ + outliner_context_selected_ids_recursive(&space_outliner->tree, result); + CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); +} + +static const char *outliner_context_dir[] = {"selected_ids", NULL}; + +int /*eContextResult*/ outliner_context(const bContext *C, + const char *member, + bContextDataResult *result) +{ + SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); + + if (CTX_data_dir(member)) { + CTX_data_dir_set(result, outliner_context_dir); + return CTX_RESULT_OK; + } + if (CTX_data_equals(member, "selected_ids")) { + outliner_context_selected_ids(space_outliner, result); + return CTX_RESULT_OK; + } + /* Note: Querying non-ID selection could also work if tree elements stored their matching RNA + * struct type. */ + + return CTX_RESULT_MEMBER_NOT_FOUND; +} diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c index d3da7b80765..152bbc96281 100644 --- a/source/blender/editors/space_outliner/outliner_dragdrop.c +++ b/source/blender/editors/space_outliner/outliner_dragdrop.c @@ -333,7 +333,7 @@ static bool parent_drop_poll(bContext *C, ED_region_tag_redraw_no_rebuild(CTX_wm_region(C)); } - Object *potential_child = (Object *)WM_drag_ID(drag, ID_OB); + Object *potential_child = (Object *)WM_drag_get_local_ID(drag, ID_OB); if (!potential_child) { return false; } @@ -421,7 +421,7 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) } Object *par = (Object *)tselem->id; - Object *ob = (Object *)WM_drag_ID_from_event(event, ID_OB); + Object *ob = (Object *)WM_drag_get_local_ID_from_event(event, ID_OB); if (ELEM(NULL, ob, par)) { return OPERATOR_CANCELLED; @@ -445,7 +445,7 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) void OUTLINER_OT_parent_drop(wmOperatorType *ot) { /* identifiers */ - ot->name = "Drop to Set Parent [+Alt keeps transforms]"; + ot->name = "Drop to Set Parent (hold Alt to keep transforms)"; ot->description = "Drag to parent in Outliner"; ot->idname = "OUTLINER_OT_parent_drop"; @@ -473,7 +473,7 @@ static bool parent_clear_poll(bContext *C, } } - Object *ob = (Object *)WM_drag_ID(drag, ID_OB); + Object *ob = (Object *)WM_drag_get_local_ID(drag, ID_OB); if (!ob) { return false; } @@ -531,7 +531,7 @@ static int parent_clear_invoke(bContext *C, wmOperator *UNUSED(op), const wmEven void OUTLINER_OT_parent_clear(wmOperatorType *ot) { /* identifiers */ - ot->name = "Drop to Clear Parent [+Alt keeps transforms]"; + ot->name = "Drop to Clear Parent (hold Alt to keep transforms)"; ot->description = "Drag to clear parent in Outliner"; ot->idname = "OUTLINER_OT_parent_clear"; @@ -552,7 +552,7 @@ static bool scene_drop_poll(bContext *C, const char **UNUSED(r_tooltip)) { /* Ensure item under cursor is valid drop target */ - Object *ob = (Object *)WM_drag_ID(drag, ID_OB); + Object *ob = (Object *)WM_drag_get_local_ID(drag, ID_OB); return (ob && (outliner_ID_drop_find(C, event, ID_SCE) != NULL)); } @@ -560,7 +560,7 @@ static int scene_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent { Main *bmain = CTX_data_main(C); Scene *scene = (Scene *)outliner_ID_drop_find(C, event, ID_SCE); - Object *ob = (Object *)WM_drag_ID_from_event(event, ID_OB); + Object *ob = (Object *)WM_drag_get_local_ID_from_event(event, ID_OB); if (ELEM(NULL, ob, scene) || ID_IS_LINKED(scene)) { return OPERATOR_CANCELLED; @@ -620,7 +620,7 @@ static bool material_drop_poll(bContext *C, const char **UNUSED(r_tooltip)) { /* Ensure item under cursor is valid drop target */ - Material *ma = (Material *)WM_drag_ID(drag, ID_MA); + Material *ma = (Material *)WM_drag_get_local_ID(drag, ID_MA); return (ma && (outliner_ID_drop_find(C, event, ID_OB) != NULL)); } @@ -628,7 +628,7 @@ static int material_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEve { Main *bmain = CTX_data_main(C); Object *ob = (Object *)outliner_ID_drop_find(C, event, ID_OB); - Material *ma = (Material *)WM_drag_ID_from_event(event, ID_MA); + Material *ma = (Material *)WM_drag_get_local_ID_from_event(event, ID_MA); if (ELEM(NULL, ob, ma)) { return OPERATOR_CANCELLED; @@ -1461,14 +1461,14 @@ static int outliner_item_drag_drop_invoke(bContext *C, parent = scene->master_collection; } - WM_drag_add_ID(drag, id, &parent->id); + WM_drag_add_local_ID(drag, id, &parent->id); } BLI_freelistN(&selected.selected_array); } else { /* Add single ID. */ - WM_drag_add_ID(drag, data.drag_id, data.drag_parent); + WM_drag_add_local_ID(drag, data.drag_id, data.drag_parent); } ED_outliner_select_sync_from_outliner(C, space_outliner); diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 6364fbc0a87..9223da136e1 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -1996,7 +1996,7 @@ static void outliner_draw_mode_column_toggle(uiBlock *block, "Change the object in the current mode\n" "* Ctrl to add to the current mode"); } - + UI_block_emboss_set(block, UI_EMBOSS_NONE_OR_STATUS); uiBut *but = uiDefIconBut(block, UI_BTYPE_ICON_TOGGLE, 0, @@ -2845,6 +2845,7 @@ static void outliner_draw_iconrow(bContext *C, LISTBASE_FOREACH (TreeElement *, te, lb) { TreeStoreElem *tselem = TREESTORE(te); + te->flag &= ~(TE_ICONROW | TE_ICONROW_MERGED); /* object hierarchy always, further constrained on level */ if (level < 1 || (tselem->type == 0 && te->idcode == ID_OB)) { @@ -2928,8 +2929,6 @@ static void outliner_draw_iconrow(bContext *C, /* closed tree element */ static void outliner_set_coord_tree_element(TreeElement *te, int startx, int starty) { - TreeElement *ten; - /* closed items may be displayed in row of parent, don't change their coordinate! */ if ((te->flag & TE_ICONROW) == 0 && (te->flag & TE_ICONROW_MERGED) == 0) { te->xs = 0; @@ -2937,7 +2936,7 @@ static void outliner_set_coord_tree_element(TreeElement *te, int startx, int sta te->xend = 0; } - for (ten = te->subtree.first; ten; ten = ten->next) { + LISTBASE_FOREACH (TreeElement *, ten, &te->subtree) { outliner_set_coord_tree_element(ten, startx + UI_UNIT_X, starty); } } @@ -3647,7 +3646,7 @@ void draw_outliner(const bContext *C) outliner_tree_dimensions(space_outliner, &tree_width, &tree_height); /* Default to no emboss for outliner UI. */ - UI_block_emboss_set(block, UI_EMBOSS_NONE); + UI_block_emboss_set(block, UI_EMBOSS_NONE_OR_STATUS); if (space_outliner->outlinevis == SO_DATA_API) { int buttons_start_x = outliner_data_api_buttons_start_x(tree_width); @@ -3656,7 +3655,7 @@ void draw_outliner(const bContext *C) UI_block_emboss_set(block, UI_EMBOSS); outliner_draw_rnabuts(block, region, space_outliner, buttons_start_x, &space_outliner->tree); - UI_block_emboss_set(block, UI_EMBOSS_NONE); + UI_block_emboss_set(block, UI_EMBOSS_NONE_OR_STATUS); } else if (space_outliner->outlinevis == SO_ID_ORPHANS) { /* draw user toggle columns */ diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index a1ff6193cd0..1cb98e704f2 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -1253,8 +1253,7 @@ static void outliner_set_coordinates_element_recursive(SpaceOutliner *space_outl *starty -= UI_UNIT_Y; if (TSELEM_OPEN(tselem, space_outliner)) { - TreeElement *ten; - for (ten = te->subtree.first; ten; ten = ten->next) { + LISTBASE_FOREACH (TreeElement *, ten, &te->subtree) { outliner_set_coordinates_element_recursive(space_outliner, ten, startx + UI_UNIT_X, starty); } } @@ -1753,7 +1752,7 @@ static void tree_element_to_path(TreeElement *te, { ListBase hierarchy = {NULL, NULL}; LinkData *ld; - TreeElement *tem, *temnext, *temsub; + TreeElement *tem, *temnext; TreeStoreElem *tse /* , *tsenext */ /* UNUSED */; PointerRNA *ptr, *nextptr; PropertyRNA *prop; @@ -1823,7 +1822,7 @@ static void tree_element_to_path(TreeElement *te, /* otherwise use index */ int index = 0; - for (temsub = tem->subtree.first; temsub; temsub = temsub->next, index++) { + LISTBASE_FOREACH (TreeElement *, temsub, &tem->subtree) { if (temsub == temnext) { break; } diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index 0294b4836c8..339cc3068d0 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -42,6 +42,7 @@ struct TreeElement; struct TreeStoreElem; struct ViewLayer; struct bContext; +struct bContextDataResult; struct bPoseChannel; struct wmKeyConfig; struct wmOperatorType; @@ -561,6 +562,12 @@ void outliner_tag_redraw_avoid_rebuild_on_open_change(const struct SpaceOutliner void outliner_sync_selection(const struct bContext *C, struct SpaceOutliner *space_outliner); +/* outliner_context.c ------------------------------------------- */ + +int outliner_context(const struct bContext *C, + const char *member, + struct bContextDataResult *result); + #ifdef __cplusplus } #endif diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index fa8bce9df6a..6380bb9505e 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -72,6 +72,7 @@ #include "ED_sequencer.h" #include "ED_undo.h" +#include "SEQ_select.h" #include "SEQ_sequencer.h" #include "WM_api.h" @@ -870,13 +871,13 @@ static eOLDrawState tree_element_active_sequence(bContext *C, const eOLSetState set) { Sequence *seq = (Sequence *)te->directdata; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (set != OL_SETSEL_NONE) { /* only check on setting */ if (BLI_findindex(ed->seqbasep, seq) != -1) { if (set == OL_SETSEL_EXTEND) { - BKE_sequencer_active_set(scene, NULL); + SEQ_select_active_set(scene, NULL); } ED_sequencer_deselect_all(scene); @@ -885,7 +886,7 @@ static eOLDrawState tree_element_active_sequence(bContext *C, } else { seq->flag |= SELECT; - BKE_sequencer_active_set(scene, seq); + SEQ_select_active_set(scene, seq); } } @@ -905,7 +906,7 @@ static eOLDrawState tree_element_active_sequence_dup(Scene *scene, const eOLSetState set) { Sequence *seq, *p; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); seq = (Sequence *)te->directdata; if (set == OL_SETSEL_NONE) { @@ -1185,6 +1186,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE } else { ModifierData *md = (ModifierData *)te->directdata; + BKE_object_modifier_set_active(ob, md); switch ((ModifierType)md->type) { case eModifierType_ParticleSystem: diff --git a/source/blender/editors/space_outliner/outliner_sync.c b/source/blender/editors/space_outliner/outliner_sync.c index 0f5c74a9168..0b2d1ce34ec 100644 --- a/source/blender/editors/space_outliner/outliner_sync.c +++ b/source/blender/editors/space_outliner/outliner_sync.c @@ -46,7 +46,7 @@ #include "ED_object.h" #include "ED_outliner.h" -#include "SEQ_sequencer.h" +#include "SEQ_select.h" #include "WM_api.h" #include "WM_types.h" @@ -305,7 +305,7 @@ static void outliner_select_sync_to_sequence(Scene *scene, TreeStoreElem *tselem Sequence *seq = (Sequence *)tselem->id; if (tselem->flag & TSE_ACTIVE) { - BKE_sequencer_active_set(scene, seq); + SEQ_select_active_set(scene, seq); } if (tselem->flag & TSE_SELECTED) { @@ -542,7 +542,7 @@ static void get_sync_select_active_data(const bContext *C, SyncSelectActiveData active_data->object = OBACT(view_layer); active_data->edit_bone = CTX_data_active_bone(C); active_data->pose_channel = CTX_data_active_pose_bone(C); - active_data->sequence = BKE_sequencer_active_get(scene); + active_data->sequence = SEQ_select_active_get(scene); } /* If outliner is dirty sync selection from view layer and sequwncer */ diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index 159a4616ba7..d4784a509bf 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -737,7 +737,7 @@ static void id_local_fn(bContext *C, } static void object_proxy_to_override_convert_fn(bContext *C, - ReportList *UNUSED(reports), + ReportList *reports, Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), @@ -754,8 +754,15 @@ static void object_proxy_to_override_convert_fn(bContext *C, return; } - BKE_lib_override_library_proxy_convert( - CTX_data_main(C), scene, CTX_data_view_layer(C), ob_proxy); + if (!BKE_lib_override_library_proxy_convert( + CTX_data_main(C), scene, CTX_data_view_layer(C), ob_proxy)) { + BKE_reportf( + reports, + RPT_ERROR_INVALID_INPUT, + "Could not create a library override from proxy '%s' (might use already local data?)", + ob_proxy->id.name + 2); + return; + } DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS | ID_RECALC_COPY_ON_WRITE); WM_event_add_notifier(C, NC_WINDOW, NULL); @@ -1199,7 +1206,7 @@ static void sequence_fn(int event, TreeElement *te, TreeStoreElem *tselem, void Sequence *seq = (Sequence *)te->directdata; if (event == OL_DOP_SELECT) { Scene *scene = (Scene *)scene_ptr; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (BLI_findindex(ed->seqbasep, seq) != -1) { ED_sequencer_select_sequence_single(scene, seq, true); } @@ -1685,6 +1692,8 @@ typedef enum eOutlinerIdOpTypes { OUTLINER_IDOP_INVALID = 0, OUTLINER_IDOP_UNLINK, + OUTLINER_IDOP_MARK_ASSET, + OUTLINER_IDOP_CLEAR_ASSET, OUTLINER_IDOP_LOCAL, OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE, OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY, @@ -1710,6 +1719,8 @@ typedef enum eOutlinerIdOpTypes { /* TODO: implement support for changing the ID-block used. */ static const EnumPropertyItem prop_id_op_types[] = { {OUTLINER_IDOP_UNLINK, "UNLINK", 0, "Unlink", ""}, + {OUTLINER_IDOP_MARK_ASSET, "MARK_ASSET", 0, "Mark Asset", ""}, + {OUTLINER_IDOP_CLEAR_ASSET, "CLEAR_ASSET", 0, "Clear Asset", ""}, {OUTLINER_IDOP_LOCAL, "LOCAL", 0, "Make Local", ""}, {OUTLINER_IDOP_SINGLE, "SINGLE", 0, "Make Single User", ""}, {OUTLINER_IDOP_DELETE, "DELETE", ICON_X, "Delete", ""}, @@ -1915,6 +1926,14 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) } break; } + case OUTLINER_IDOP_MARK_ASSET: { + WM_operator_name_call(C, "ASSET_OT_mark", WM_OP_EXEC_DEFAULT, NULL); + break; + } + case OUTLINER_IDOP_CLEAR_ASSET: { + WM_operator_name_call(C, "ASSET_OT_clear", WM_OP_EXEC_DEFAULT, NULL); + break; + } case OUTLINER_IDOP_LOCAL: { /* make local */ outliner_do_libdata_operation( @@ -2791,7 +2810,7 @@ static int do_outliner_operation_event(bContext *C, } if (datalevel == TSE_ID_BASE) { /* do nothing... there are no ops needed here yet */ - return 0; + return OPERATOR_CANCELLED; } if (datalevel == TSE_CONSTRAINT) { return outliner_operator_menu(C, "OUTLINER_OT_constraint_operation"); @@ -2802,7 +2821,7 @@ static int do_outliner_operation_event(bContext *C, return outliner_operator_menu(C, "OUTLINER_OT_data_operation"); } - return 0; + return OPERATOR_CANCELLED; } static int outliner_operation(bContext *C, wmOperator *op, const wmEvent *event) diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 7308b161d18..56eedcd3748 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -908,9 +908,9 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner, /** * TODO: this function needs to be split up! It's getting a bit too large... * - * \note: "ID" is not always a real ID - * \note: If child items are only added to the tree if the item is open, the TSE_ type _must_ be - * added to #outliner_element_needs_rebuild_on_open_change(). + * \note "ID" is not always a real ID. + * \note If child items are only added to the tree if the item is open, + * the `TSE_` type _must_ be added to #outliner_element_needs_rebuild_on_open_change(). */ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, ListBase *lb, diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index 3d675fdd9e4..c7c207caca0 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -451,6 +451,7 @@ void ED_spacetype_outliner(void) st->dropboxes = outliner_dropboxes; st->id_remap = outliner_id_remap; st->deactivate = outliner_deactivate; + st->context = outliner_context; /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype outliner region"); diff --git a/source/blender/editors/space_outliner/tree/tree_display_data.cc b/source/blender/editors/space_outliner/tree/tree_display_data.cc index 41ca4f72903..8a5c2e7d9f3 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_data.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_data.cc @@ -41,7 +41,7 @@ ListBase TreeDisplayDataAPI::buildTree(const TreeSourceData &source_data) RNA_main_pointer_create(source_data.bmain, &mainptr); TreeElement *te = outliner_add_element( - &space_outliner_, &tree, (void *)&mainptr, NULL, TSE_RNA_STRUCT, -1); + &space_outliner_, &tree, (void *)&mainptr, nullptr, TSE_RNA_STRUCT, -1); /* On first view open parent data elements */ const int show_opened = !space_outliner_.treestore || diff --git a/source/blender/editors/space_outliner/tree/tree_display_libraries.cc b/source/blender/editors/space_outliner/tree/tree_display_libraries.cc index bd0870c837c..cb5f42f08e1 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_libraries.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_libraries.cc @@ -24,6 +24,8 @@ #include "BKE_collection.h" #include "BKE_main.h" +#include "DNA_collection_types.h" + #include "BLT_translation.h" #include "../outliner_intern.h" diff --git a/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc b/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc index 71c1d344057..0b17ea98831 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc @@ -68,7 +68,7 @@ ListBase TreeDisplayIDOrphans::buildTree(const TreeSourceData &source_data) TreeElement *te = nullptr; if (!filter_id_type) { ID *id = (ID *)lbarray[a]->first; - te = outliner_add_element(&space_outliner_, &tree, lbarray[a], NULL, TSE_ID_BASE, 0); + te = outliner_add_element(&space_outliner_, &tree, lbarray[a], nullptr, TSE_ID_BASE, 0); te->directdata = lbarray[a]; te->name = outliner_idcode_to_plural(GS(id->name)); } diff --git a/source/blender/editors/space_outliner/tree/tree_display_scenes.cc b/source/blender/editors/space_outliner/tree/tree_display_scenes.cc index c4a5688504d..f377512d81e 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_scenes.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_scenes.cc @@ -46,7 +46,7 @@ ListBase TreeDisplayScenes::buildTree(const TreeSourceData &source_data) for (ID *id : List<ID>(source_data.bmain->scenes)) { Scene *scene = reinterpret_cast<Scene *>(id); - TreeElement *te = outliner_add_element(&space_outliner_, &tree, scene, NULL, 0, 0); + TreeElement *te = outliner_add_element(&space_outliner_, &tree, scene, nullptr, 0, 0); TreeStoreElem *tselem = TREESTORE(te); /* New scene elements open by default */ @@ -60,4 +60,4 @@ ListBase TreeDisplayScenes::buildTree(const TreeSourceData &source_data) return tree; } -} // namespace blender::ed::outliner
\ No newline at end of file +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc b/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc index 486f735be9f..40f329d72c3 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc @@ -18,7 +18,7 @@ * \ingroup spoutliner */ -#include <string.h> +#include <cstring> #include "BLI_listbase.h" #include "BLI_listbase_wrapper.hh" @@ -43,7 +43,7 @@ ListBase TreeDisplaySequencer::buildTree(const TreeSourceData &source_data) { ListBase tree = {nullptr}; - Editing *ed = BKE_sequencer_editing_get(source_data.scene, false); + Editing *ed = SEQ_editing_get(source_data.scene, false); if (ed == nullptr) { return tree; } @@ -51,11 +51,11 @@ ListBase TreeDisplaySequencer::buildTree(const TreeSourceData &source_data) for (Sequence *seq : List<Sequence>(ed->seqbasep)) { SequenceAddOp op = need_add_seq_dup(seq); if (op == SEQUENCE_DUPLICATE_NONE) { - outliner_add_element(&space_outliner_, &tree, seq, NULL, TSE_SEQUENCE, 0); + outliner_add_element(&space_outliner_, &tree, seq, nullptr, TSE_SEQUENCE, 0); } else if (op == SEQUENCE_DUPLICATE_ADD) { TreeElement *te = outliner_add_element( - &space_outliner_, &tree, seq, NULL, TSE_SEQUENCE_DUP, 0); + &space_outliner_, &tree, seq, nullptr, TSE_SEQUENCE_DUP, 0); add_seq_dup(seq, te, 0); } } diff --git a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc index c88eb957dd1..f7740f4648f 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc @@ -20,6 +20,7 @@ #include <iostream> +#include "DNA_collection_types.h" #include "DNA_scene_types.h" #include "BKE_layer.h" diff --git a/source/blender/editors/space_outliner/tree/tree_element.h b/source/blender/editors/space_outliner/tree/tree_element.h index 9012321a323..d88c37180b3 100644 --- a/source/blender/editors/space_outliner/tree/tree_element.h +++ b/source/blender/editors/space_outliner/tree/tree_element.h @@ -36,7 +36,7 @@ extern "C" { typedef struct TreeElementType TreeElementType; TreeElementType *outliner_tree_element_type_create(int type, TreeElement *legacy_te, void *idv); -void outliner_tree_element_type_free(TreeElementType **element); +void outliner_tree_element_type_free(TreeElementType **type); void outliner_tree_element_type_expand(TreeElementType *type, SpaceOutliner *space_outliner); diff --git a/source/blender/editors/space_outliner/tree/tree_element_nla.hh b/source/blender/editors/space_outliner/tree/tree_element_nla.hh index 3ca62b13bd8..c94287ce576 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_nla.hh +++ b/source/blender/editors/space_outliner/tree/tree_element_nla.hh @@ -23,7 +23,6 @@ #include "tree_element.hh" struct NlaTrack; -struct NlaStrip; namespace blender::ed::outliner { diff --git a/source/blender/editors/space_script/script_edit.c b/source/blender/editors/space_script/script_edit.c index bde7bdb77f1..50cfa2e71c7 100644 --- a/source/blender/editors/space_script/script_edit.c +++ b/source/blender/editors/space_script/script_edit.c @@ -152,7 +152,7 @@ void SCRIPT_OT_reload(wmOperatorType *ot) { /* identifiers */ ot->name = "Reload Scripts"; - ot->description = "Reload Scripts"; + ot->description = "Reload scripts"; ot->idname = "SCRIPT_OT_reload"; /* api callbacks */ diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index 37dfcdbc765..f9076145f2f 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -50,7 +50,15 @@ #include "RNA_define.h" #include "RNA_enum_types.h" +#include "SEQ_add.h" +#include "SEQ_effects.h" +#include "SEQ_relations.h" +#include "SEQ_render.h" +#include "SEQ_select.h" #include "SEQ_sequencer.h" +#include "SEQ_time.h" +#include "SEQ_transform.h" +#include "SEQ_utils.h" /* For menu, popup, icons, etc. */ #include "ED_screen.h" @@ -81,9 +89,18 @@ typedef struct SequencerAddData { #define SEQPROP_ENDFRAME (1 << 1) #define SEQPROP_NOPATHS (1 << 2) #define SEQPROP_NOCHAN (1 << 3) +#define SEQPROP_FIT_METHOD (1 << 4) #define SELECT 1 +static const EnumPropertyItem scale_fit_methods[] = { + {SEQ_SCALE_TO_FIT, "FIT", 0, "Scale to Fit", "Scale image to fit within the canvas"}, + {SEQ_SCALE_TO_FILL, "FILL", 0, "Scale to Fill", "Scale image to completely fill the canvas"}, + {SEQ_STRETCH_TO_FILL, "STRETCH", 0, "Stretch to Fill", "Stretch image to fill the canvas"}, + {SEQ_USE_ORIGINAL_SIZE, "ORIGINAL", 0, "Use Original Size", "Keep image at its original size"}, + {0, NULL, 0, NULL, NULL}, +}; + static void sequencer_generic_props__internal(wmOperatorType *ot, int flag) { PropertyRNA *prop; @@ -123,6 +140,15 @@ static void sequencer_generic_props__internal(wmOperatorType *ot, int flag) prop = RNA_def_boolean( ot->srna, "overlap", 0, "Allow Overlap", "Don't correct overlap on new sequence strips"); RNA_def_property_flag(prop, PROP_HIDDEN); + + if (flag & SEQPROP_FIT_METHOD) { + ot->prop = RNA_def_enum(ot->srna, + "fit_method", + scale_fit_methods, + SEQ_SCALE_TO_FIT, + "Fit Method", + "Scale fit method"); + } } static void sequencer_generic_invoke_path__internal(bContext *C, @@ -131,7 +157,7 @@ static void sequencer_generic_invoke_path__internal(bContext *C, { if (RNA_struct_find_property(op->ptr, identifier)) { Scene *scene = CTX_data_scene(C); - Sequence *last_seq = BKE_sequencer_active_get(scene); + Sequence *last_seq = SEQ_select_active_get(scene); if (last_seq && last_seq->strip && SEQ_HAS_PATH(last_seq)) { Main *bmain = CTX_data_main(C); char path[FILE_MAX]; @@ -147,7 +173,7 @@ static int sequencer_generic_invoke_xy_guess_channel(bContext *C, int type) Sequence *tgt = NULL; Sequence *seq; Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, true); + Editing *ed = SEQ_editing_get(scene, true); int timeline_frame = (int)CFRA; int proximity = INT_MAX; @@ -206,6 +232,8 @@ static void seq_load_operator_info(SeqLoadInfo *seq_load, bContext *C, wmOperato seq_load->end_frame = seq_load->start_frame; seq_load->channel = RNA_int_get(op->ptr, "channel"); seq_load->len = 1; + seq_load->fit_method = RNA_enum_get(op->ptr, "fit_method"); + SEQ_tool_settings_fit_method_set(CTX_data_scene(C), seq_load->fit_method); if ((prop = RNA_struct_find_property(op->ptr, "filepath"))) { /* Full path, file is set by the caller. */ @@ -286,11 +314,11 @@ static void seq_load_operator_info(SeqLoadInfo *seq_load, bContext *C, wmOperato static void sequencer_add_apply_overlap(bContext *C, wmOperator *op, Sequence *seq) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (RNA_boolean_get(op->ptr, "overlap") == false) { - if (BKE_sequence_test_overlap(ed->seqbasep, seq)) { - BKE_sequence_base_shuffle(ed->seqbasep, seq, scene); + if (SEQ_transform_test_overlap(ed->seqbasep, seq)) { + SEQ_transform_seqbase_shuffle(ed->seqbasep, seq, scene); } } } @@ -301,7 +329,7 @@ static void sequencer_add_apply_replace_sel(bContext *C, wmOperator *op, Sequenc if (RNA_boolean_get(op->ptr, "replace_sel")) { ED_sequencer_deselect_all(scene); - BKE_sequencer_active_set(scene, seq); + SEQ_select_active_set(scene, seq); seq->flag |= SELECT; } } @@ -314,7 +342,7 @@ static bool seq_effect_add_properties_poll(const bContext *UNUSED(C), int type = RNA_enum_get(op->ptr, "type"); /* Hide start/end frames for effect strips that are locked to their parents' location. */ - if (BKE_sequence_effect_get_num_inputs(type) != 0) { + if (SEQ_effect_get_num_inputs(type) != 0) { if (STR_ELEM(prop_id, "frame_start", "frame_end")) { return false; } @@ -330,7 +358,7 @@ static int sequencer_add_scene_strip_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, true); + Editing *ed = SEQ_editing_get(scene, true); Scene *sce_seq; Sequence *seq; @@ -344,20 +372,20 @@ static int sequencer_add_scene_strip_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - seq = BKE_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_SCENE); + seq = SEQ_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_SCENE); seq->blend_mode = SEQ_TYPE_CROSS; seq->scene = sce_seq; seq->len = sce_seq->r.efra - sce_seq->r.sfra + 1; BLI_strncpy(seq->name + 2, sce_seq->id.name + 2, sizeof(seq->name) - 2); - BKE_sequence_base_unique_name_recursive(&ed->seqbase, seq); + SEQ_sequence_base_unique_name_recursive(&ed->seqbase, seq); - BKE_sequence_calc_disp(scene, seq); - BKE_sequencer_sort(scene); + SEQ_time_update_sequence_bounds(scene, seq); + SEQ_sort(scene); sequencer_add_apply_replace_sel(C, op, seq); sequencer_add_apply_overlap(C, op, seq); - BKE_sequence_invalidate_cache_composite(scene, seq); + SEQ_relations_invalidate_cache_composite(scene, seq); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); DEG_relations_tag_update(bmain); @@ -404,7 +432,7 @@ static int sequencer_add_movieclip_strip_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, true); + Editing *ed = SEQ_editing_get(scene, true); MovieClip *clip; Sequence *seq; @@ -418,7 +446,7 @@ static int sequencer_add_movieclip_strip_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - seq = BKE_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_MOVIECLIP); + seq = SEQ_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_MOVIECLIP); seq->blend_mode = SEQ_TYPE_CROSS; seq->clip = clip; seq->len = BKE_movieclip_get_duration(clip); @@ -426,14 +454,14 @@ static int sequencer_add_movieclip_strip_exec(bContext *C, wmOperator *op) id_us_ensure_real(&seq->clip->id); BLI_strncpy(seq->name + 2, clip->id.name + 2, sizeof(seq->name) - 2); - BKE_sequence_base_unique_name_recursive(&ed->seqbase, seq); + SEQ_sequence_base_unique_name_recursive(&ed->seqbase, seq); - BKE_sequence_calc_disp(scene, seq); - BKE_sequencer_sort(scene); + SEQ_time_update_sequence_bounds(scene, seq); + SEQ_sort(scene); sequencer_add_apply_replace_sel(C, op, seq); sequencer_add_apply_overlap(C, op, seq); - BKE_sequence_invalidate_cache_composite(scene, seq); + SEQ_relations_invalidate_cache_composite(scene, seq); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -480,7 +508,7 @@ static int sequencer_add_mask_strip_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, true); + Editing *ed = SEQ_editing_get(scene, true); Mask *mask; Sequence *seq; @@ -494,7 +522,7 @@ static int sequencer_add_mask_strip_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - seq = BKE_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_MASK); + seq = SEQ_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_MASK); seq->blend_mode = SEQ_TYPE_CROSS; seq->mask = mask; seq->len = BKE_mask_get_duration(mask); @@ -502,14 +530,14 @@ static int sequencer_add_mask_strip_exec(bContext *C, wmOperator *op) id_us_ensure_real(&seq->mask->id); BLI_strncpy(seq->name + 2, mask->id.name + 2, sizeof(seq->name) - 2); - BKE_sequence_base_unique_name_recursive(&ed->seqbase, seq); + SEQ_sequence_base_unique_name_recursive(&ed->seqbase, seq); - BKE_sequence_calc_disp(scene, seq); - BKE_sequencer_sort(scene); + SEQ_time_update_sequence_bounds(scene, seq); + SEQ_sort(scene); sequencer_add_apply_replace_sel(C, op, seq); sequencer_add_apply_overlap(C, op, seq); - BKE_sequence_invalidate_cache_composite(scene, seq); + SEQ_relations_invalidate_cache_composite(scene, seq); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -554,7 +582,7 @@ void SEQUENCER_OT_mask_strip_add(struct wmOperatorType *ot) static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoadFn seq_load_fn) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, true); + Editing *ed = SEQ_editing_get(scene, true); SeqLoadInfo seq_load; int tot_files; @@ -612,7 +640,7 @@ static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoad return OPERATOR_CANCELLED; } - BKE_sequencer_sort(scene); + SEQ_sort(scene); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -644,7 +672,7 @@ static bool sequencer_add_draw_check_fn(PointerRNA *UNUSED(ptr), static int sequencer_add_movie_strip_exec(bContext *C, wmOperator *op) { - return sequencer_add_generic_strip_exec(C, op, BKE_sequencer_add_movie_strip); + return sequencer_add_generic_strip_exec(C, op, SEQ_add_movie_strip); } static int sequencer_add_movie_strip_invoke(bContext *C, @@ -653,12 +681,13 @@ static int sequencer_add_movie_strip_invoke(bContext *C, { PropertyRNA *prop; Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); /* Only enable "use_framerate" if there aren't any existing strips, unless overridden by user. */ if (ed && ed->seqbasep && ed->seqbasep->first) { RNA_boolean_set(op->ptr, "use_framerate", false); } + RNA_enum_set(op->ptr, "fit_method", SEQ_tool_settings_fit_method_get(scene)); /* This is for drag and drop. */ if ((RNA_struct_property_is_set(op->ptr, "files") && RNA_collection_length(op->ptr, "files")) || @@ -725,7 +754,7 @@ void SEQUENCER_OT_movie_strip_add(struct wmOperatorType *ot) WM_FILESEL_SHOW_PROPS | WM_FILESEL_DIRECTORY, FILE_DEFAULTDISPLAY, FILE_SORT_DEFAULT); - sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME); + sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME | SEQPROP_FIT_METHOD); RNA_def_boolean(ot->srna, "sound", true, "Sound", "Load sound with the movie"); RNA_def_boolean(ot->srna, "use_framerate", @@ -736,7 +765,7 @@ void SEQUENCER_OT_movie_strip_add(struct wmOperatorType *ot) static int sequencer_add_sound_strip_exec(bContext *C, wmOperator *op) { - return sequencer_add_generic_strip_exec(C, op, BKE_sequencer_add_sound_strip); + return sequencer_add_generic_strip_exec(C, op, SEQ_add_sound_strip); } static int sequencer_add_sound_strip_invoke(bContext *C, @@ -850,7 +879,7 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op) { int minframe, numdigits; Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, true); + Editing *ed = SEQ_editing_get(scene, true); SeqLoadInfo seq_load; Sequence *seq; Strip *strip; @@ -878,7 +907,7 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op) } /* Main adding function. */ - seq = BKE_sequencer_add_image_strip(C, ed->seqbasep, &seq_load); + seq = SEQ_add_image_strip(C, ed->seqbasep, &seq_load); strip = seq->strip; se = strip->stripdata; seq->blend_mode = SEQ_TYPE_ALPHAOVER; @@ -903,8 +932,8 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op) } SEQ_render_init_colorspace(seq); - BKE_sequence_calc_disp(scene, seq); - BKE_sequencer_sort(scene); + SEQ_time_update_sequence_bounds(scene, seq); + SEQ_sort(scene); /* Last active name. */ BLI_strncpy(ed->act_imagedir, strip->dir, sizeof(ed->act_imagedir)); @@ -914,7 +943,7 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op) MEM_freeN(op->customdata); } - BKE_sequence_invalidate_cache_composite(scene, seq); + SEQ_relations_invalidate_cache_composite(scene, seq); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -928,6 +957,9 @@ static int sequencer_add_image_strip_invoke(bContext *C, PropertyRNA *prop; Scene *scene = CTX_data_scene(C); + const SequencerToolSettings *tool_settings = scene->toolsettings->sequencer_tool_settings; + RNA_enum_set(op->ptr, "fit_method", tool_settings->fit_method); + /* Name set already by drag and drop. */ if (RNA_struct_property_is_set(op->ptr, "files") && RNA_collection_length(op->ptr, "files")) { sequencer_generic_invoke_xy__internal( @@ -972,7 +1004,8 @@ void SEQUENCER_OT_image_strip_add(struct wmOperatorType *ot) WM_FILESEL_SHOW_PROPS | WM_FILESEL_DIRECTORY, FILE_DEFAULTDISPLAY, FILE_SORT_DEFAULT); - sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME | SEQPROP_ENDFRAME); + sequencer_generic_props__internal(ot, + SEQPROP_STARTFRAME | SEQPROP_ENDFRAME | SEQPROP_FIT_METHOD); RNA_def_boolean(ot->srna, "use_placeholders", @@ -984,7 +1017,7 @@ void SEQUENCER_OT_image_strip_add(struct wmOperatorType *ot) static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, true); + Editing *ed = SEQ_editing_get(scene, true); Sequence *seq; struct SeqEffectHandle sh; Sequence *seq1, *seq2, *seq3; @@ -1007,11 +1040,11 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op) RNA_int_set(op->ptr, "frame_end", end_frame); } - seq = BKE_sequence_alloc(ed->seqbasep, start_frame, channel, type); - BLI_strncpy(seq->name + 2, BKE_sequence_give_name(seq), sizeof(seq->name) - 2); - BKE_sequence_base_unique_name_recursive(&ed->seqbase, seq); + seq = SEQ_sequence_alloc(ed->seqbasep, start_frame, channel, type); + BLI_strncpy(seq->name + 2, SEQ_sequence_give_name(seq), sizeof(seq->name) - 2); + SEQ_sequence_base_unique_name_recursive(&ed->seqbase, seq); - sh = BKE_sequence_get_effect(seq); + sh = SEQ_effect_handle_get(seq); sh.init(seq); seq->seq1 = seq1; seq->seq2 = seq2; @@ -1019,11 +1052,11 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op) if (!seq1) { seq->len = 1; /* Effect is generator, set non zero length. */ - BKE_sequence_tx_set_final_right(seq, end_frame); + SEQ_transform_set_right_handle_frame(seq, end_frame); } seq->flag |= SEQ_USE_EFFECT_DEFAULT_FADE; - BKE_sequence_calc(scene, seq); + SEQ_time_update_sequence(scene, seq); if (seq->type == SEQ_TYPE_COLOR) { SolidColorVars *colvars = (SolidColorVars *)seq->effectdata; @@ -1052,10 +1085,10 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op) sequencer_add_apply_replace_sel(C, op, seq); sequencer_add_apply_overlap(C, op, seq); - BKE_sequencer_update_changed_seq_and_deps(scene, seq, 1, 1); /* Runs BKE_sequence_calc. */ - BKE_sequencer_sort(scene); + SEQ_relations_update_changed_seq_and_deps(scene, seq, 1, 1); /* Runs SEQ_time_update_sequence. */ + SEQ_sort(scene); - BKE_sequence_invalidate_cache_composite(scene, seq); + SEQ_relations_invalidate_cache_composite(scene, seq); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -1075,7 +1108,7 @@ static int sequencer_add_effect_strip_invoke(bContext *C, /* When invoking an effect strip which uses inputs, skip initializing the channel from the * mouse. */ - if (BKE_sequence_effect_get_num_inputs(type) != 0) { + if (SEQ_effect_get_num_inputs(type) != 0) { prop_flag |= SEQPROP_NOCHAN; } } diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 081714991ff..2ee0dcea5e5 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -68,7 +68,16 @@ #include "BIF_glutil.h" +#include "SEQ_effects.h" +#include "SEQ_prefetch.h" +#include "SEQ_proxy.h" +#include "SEQ_relations.h" +#include "SEQ_render.h" +#include "SEQ_select.h" #include "SEQ_sequencer.h" +#include "SEQ_time.h" +#include "SEQ_transform.h" +#include "SEQ_utils.h" #include "UI_interface.h" #include "UI_resources.h" @@ -227,16 +236,16 @@ void color3ubv_from_seq(Scene *curscene, Sequence *seq, uchar col[3]) * \param x1, x2, y1, y2: The starting and end X value to draw the wave, same for y1 and y2. * \param stepsize: The width of a pixel. */ -static void draw_seq_waveform(View2D *v2d, - const bContext *C, - SpaceSeq *sseq, - Scene *scene, - Sequence *seq, - float x1, - float y1, - float x2, - float y2, - float stepsize) +static void draw_seq_waveform_overlay(View2D *v2d, + const bContext *C, + SpaceSeq *sseq, + Scene *scene, + Sequence *seq, + float x1, + float y1, + float x2, + float y2, + float stepsize) { /* Offset x1 and x2 values, to match view min/max, if strip is out of bounds. */ int x1_offset = max_ff(v2d->cur.xmin, x1); @@ -371,7 +380,7 @@ static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1, ListBase *seqbase; int offset; - seqbase = BKE_sequence_seqbase_get(seqm, &offset); + seqbase = SEQ_get_seqbase_from_sequence(seqm, &offset); if (!seqbase || BLI_listbase_is_empty(seqbase)) { return; } @@ -488,7 +497,7 @@ static void draw_seq_handle(View2D *v2d, whichsel = SEQ_RIGHTSEL; } - if (!(seq->type & SEQ_TYPE_EFFECT) || BKE_sequence_effect_get_num_inputs(seq->type) == 0) { + if (!(seq->type & SEQ_TYPE_EFFECT) || SEQ_effect_get_num_inputs(seq->type) == 0) { GPU_blend(GPU_BLEND_ALPHA); GPU_blend(GPU_BLEND_ALPHA); @@ -603,121 +612,110 @@ static void draw_seq_outline(Sequence *seq, } } -/* Draw info text on a sequence strip. */ -static void draw_seq_text(View2D *v2d, - Sequence *seq, - SpaceSeq *sseq, - float x1, - float x2, - float y1, - float y2, - bool seq_active, - bool y_threshold) +static const char *draw_seq_text_get_name(Sequence *seq) { - rctf rect; - char str[32 + FILE_MAX]; - size_t str_len; const char *name = seq->name + 2; - uchar col[4]; - - /* All strings should include name. */ if (name[0] == '\0') { - name = BKE_sequence_give_name(seq); + name = SEQ_sequence_give_name(seq); } + return name; +} - if (ELEM(seq->type, SEQ_TYPE_META, SEQ_TYPE_ADJUSTMENT)) { - str_len = BLI_snprintf(str, sizeof(str), "%s | %d", name, seq->len); +static void draw_seq_text_get_source(Sequence *seq, char *r_source, size_t source_len) +{ + /* Set source for the most common types. */ + if (ELEM(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE)) { + BLI_snprintf(r_source, source_len, "%s%s", seq->strip->dir, seq->strip->stripdata->name); } - else if (seq->type == SEQ_TYPE_SCENE) { - if (seq->scene) { - if (seq->scene_camera) { - str_len = BLI_snprintf(str, - sizeof(str), - "%s: %s (%s) | %d", - name, - seq->scene->id.name + 2, - ((ID *)seq->scene_camera)->name + 2, - seq->len); - } - else { - str_len = BLI_snprintf( - str, sizeof(str), "%s: %s | %d", name, seq->scene->id.name + 2, seq->len); - } - } - else { - str_len = BLI_snprintf(str, sizeof(str), "%s | %d", name, seq->len); + else if (seq->type == SEQ_TYPE_SOUND_RAM) { + if (seq->sound) { + BLI_snprintf(r_source, source_len, "%s", seq->sound->filepath); } } - else if (seq->type == SEQ_TYPE_MOVIECLIP) { - if (seq->clip && !STREQ(name, seq->clip->id.name + 2)) { - str_len = BLI_snprintf( - str, sizeof(str), "%s: %s | %d", name, seq->clip->id.name + 2, seq->len); - } - else { - str_len = BLI_snprintf(str, sizeof(str), "%s | %d", name, seq->len); - } + else if (seq->type == SEQ_TYPE_MULTICAM) { + BLI_snprintf(r_source, source_len, "Channel: %d", seq->multicam_source); } - else if (seq->type == SEQ_TYPE_MASK) { - if (seq->mask && !STREQ(name, seq->mask->id.name + 2)) { - str_len = BLI_snprintf( - str, sizeof(str), "%s: %s | %d", name, seq->mask->id.name + 2, seq->len); + else if (seq->type == SEQ_TYPE_TEXT) { + TextVars *textdata = seq->effectdata; + BLI_snprintf(r_source, source_len, "%s", textdata->text); + } + else if (seq->type == SEQ_TYPE_SCENE) { + if (seq->scene_camera) { + BLI_snprintf(r_source, + source_len, + "%s (%s)", + seq->scene->id.name + 2, + ((ID *)seq->scene_camera)->name + 2); } else { - str_len = BLI_snprintf(str, sizeof(str), "%s | %d", name, seq->len); + BLI_snprintf(r_source, source_len, "%s", seq->scene->id.name + 2); } } - else if (seq->type == SEQ_TYPE_MULTICAM) { - str_len = BLI_snprintf(str, sizeof(str), "Cam %s: %d", name, seq->multicam_source); - } - else if (seq->type == SEQ_TYPE_IMAGE) { - str_len = BLI_snprintf(str, - sizeof(str), - "%s: %s%s | %d", - name, - seq->strip->dir, - seq->strip->stripdata->name, - seq->len); + else if (seq->type == SEQ_TYPE_MOVIECLIP) { + BLI_snprintf(r_source, source_len, "%s", seq->clip->id.name + 2); } - else if (seq->type == SEQ_TYPE_TEXT) { - TextVars *textdata = seq->effectdata; - str_len = BLI_snprintf(str, sizeof(str), "%s | %d", textdata->text, seq->startdisp); + else if (seq->type == SEQ_TYPE_MASK) { + BLI_snprintf(r_source, source_len, "%s", seq->mask->id.name + 2); } - else if (seq->type & SEQ_TYPE_EFFECT) { - str_len = BLI_snprintf(str, sizeof(str), "%s | %d", name, seq->len); + else { + *r_source = '\0'; } - else if (seq->type == SEQ_TYPE_SOUND_RAM) { - /* If a waveform is drawn, avoid to draw text when there is not enough vertical space. */ - if (!y_threshold && (sseq->flag & SEQ_NO_WAVEFORMS) == 0 && - ((sseq->flag & SEQ_ALL_WAVEFORMS) || (seq->flag & SEQ_AUDIO_DRAW_WAVEFORM))) { +} - str[0] = 0; - str_len = 0; - } - else if (seq->sound) { - str_len = BLI_snprintf( - str, sizeof(str), "%s: %s | %d", name, seq->sound->filepath, seq->len); +static size_t draw_seq_text_get_overlay_string(SpaceSeq *sseq, + Sequence *seq, + char *r_overlay_string, + size_t overlay_string_len) +{ + const char *name = draw_seq_text_get_name(seq); + char source[FILE_MAX]; + int strip_duration = seq->enddisp - seq->startdisp; + draw_seq_text_get_source(seq, source, sizeof(source)); + + bool show_name = sseq->flag & SEQ_SHOW_STRIP_NAME; + bool show_source = (sseq->flag & (SEQ_SHOW_STRIP_SOURCE)) && source[0] != '\0'; + bool show_duration = sseq->flag & SEQ_SHOW_STRIP_DURATION; + + size_t string_len = 0; + if (show_name) { + string_len = BLI_snprintf(r_overlay_string, overlay_string_len, "%s", name); + if (show_source || show_duration) { + string_len += BLI_snprintf(r_overlay_string + string_len, overlay_string_len, " | "); } - else { - str_len = BLI_snprintf(str, sizeof(str), "%s | %d", name, seq->len); + } + if (show_source) { + string_len += BLI_snprintf(r_overlay_string + string_len, overlay_string_len, "%s", source); + if (show_duration) { + string_len += BLI_snprintf(r_overlay_string + string_len, overlay_string_len, " | "); } } - else if (seq->type == SEQ_TYPE_MOVIE) { - str_len = BLI_snprintf(str, - sizeof(str), - "%s: %s%s | %d", - name, - seq->strip->dir, - seq->strip->stripdata->name, - seq->len); + if (show_duration) { + string_len += BLI_snprintf( + r_overlay_string + string_len, overlay_string_len, "%d", strip_duration); } - else { - /* Should never get here!, but might with files from future. */ - BLI_assert(0); + return string_len; +} + +/* Draw info text on a sequence strip. */ +static void draw_seq_text_overlay(View2D *v2d, + Sequence *seq, + SpaceSeq *sseq, + float x1, + float x2, + float y1, + float y2, + bool seq_active) +{ + char overlay_string[FILE_MAX]; + size_t overlay_string_len = draw_seq_text_get_overlay_string( + sseq, seq, overlay_string, sizeof(overlay_string)); - str_len = BLI_snprintf(str, sizeof(str), "%s | %d", name, seq->len); + if (overlay_string_len == 0) { + return; } /* White text for the active strip. */ + uchar col[4]; col[0] = col[1] = col[2] = seq_active ? 255 : 10; col[3] = 255; @@ -731,15 +729,16 @@ static void draw_seq_text(View2D *v2d, } } + rctf rect; rect.xmin = x1; rect.ymin = y1; rect.xmax = x2; rect.ymax = y2; - UI_view2d_text_cache_add_rectf(v2d, &rect, str, str_len, col); + UI_view2d_text_cache_add_rectf(v2d, &rect, overlay_string, overlay_string_len, col); } -static void draw_sequence_extensions(Scene *scene, Sequence *seq, uint pos, float pixely) +static void draw_sequence_extensions_overlay(Scene *scene, Sequence *seq, uint pos, float pixely) { float x1, x2, y1, y2; uchar col[4], blend_col[3]; @@ -850,9 +849,9 @@ static void draw_seq_background(Scene *scene, /* Draw the main strip body. */ if (is_single_image) { immRectf(pos, - BKE_sequence_tx_get_final_left(seq, false), + SEQ_transform_get_left_handle_frame(seq, false), y1, - BKE_sequence_tx_get_final_right(seq, false), + SEQ_transform_get_right_handle_frame(seq, false), y2); } else { @@ -988,7 +987,7 @@ static void fcurve_batch_add_verts(GPUVertBuf *vbo, * - Volume for sound strips. * - Opacity for the other types. */ -static void draw_seq_fcurve( +static void draw_seq_fcurve_overlay( Scene *scene, View2D *v2d, Sequence *seq, float x1, float y1, float x2, float y2, float pixelx) { FCurve *fcu; @@ -1077,7 +1076,7 @@ static void draw_seq_strip(const bContext *C, float pixely = BLI_rctf_size_y(&v2d->cur) / BLI_rcti_size_y(&v2d->mask); /* Check if we are doing "solo preview". */ - bool is_single_image = (char)BKE_sequence_single_check(seq); + bool is_single_image = (char)SEQ_transform_single_image_check(seq); /* Draw strip body. */ x1 = (seq->startstill) ? seq->start : seq->startdisp; @@ -1085,11 +1084,21 @@ static void draw_seq_strip(const bContext *C, x2 = (seq->endstill) ? (seq->start + seq->len) : seq->enddisp; y2 = seq->machine + SEQ_STRIP_OFSTOP; - /* Calculate height needed for drawing text on strip. */ - float text_margin_y = y2 - min_ff(0.40f, 20 * U.dpi_fac * pixely); + float text_margin_y; + bool y_threshold; + if ((sseq->flag & SEQ_SHOW_STRIP_NAME) || (sseq->flag & SEQ_SHOW_STRIP_SOURCE) || + (sseq->flag & SEQ_SHOW_STRIP_DURATION)) { - /* Is there enough space for drawing something else than text? */ - bool y_threshold = ((y2 - y1) / pixely) > 20 * U.dpi_fac; + /* Calculate height needed for drawing text on strip. */ + text_margin_y = y2 - min_ff(0.40f, 20 * U.dpi_fac * pixely); + + /* Is there enough space for drawing something else than text? */ + y_threshold = ((y2 - y1) / pixely) > 20 * U.dpi_fac; + } + else { + text_margin_y = y2; + y_threshold = 1; + } uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); @@ -1102,12 +1111,13 @@ static void draw_seq_strip(const bContext *C, } /* Draw strip offsets when flag is enabled or during "solo preview". */ - if (!is_single_image && (seq->startofs || seq->endofs) && pixely > 0) { - if ((sseq->draw_flag & SEQ_DRAW_OFFSET_EXT) || (seq == special_seq_update)) { - draw_sequence_extensions(scene, seq, pos, pixely); + if ((sseq->flag & SEQ_SHOW_STRIP_OVERLAY)) { + if (!is_single_image && (seq->startofs || seq->endofs) && pixely > 0) { + if ((sseq->draw_flag & SEQ_DRAW_OFFSET_EXT) || (seq == special_seq_update)) { + draw_sequence_extensions_overlay(scene, seq, pos, pixely); + } } } - immUnbindProgram(); x1 = seq->startdisp; @@ -1118,31 +1128,31 @@ static void draw_seq_strip(const bContext *C, drawmeta_contents(scene, seq, x1, y1, x2, y2); } - if (sseq->flag & SEQ_SHOW_FCURVES) { - draw_seq_fcurve(scene, v2d, seq, x1, y1, x2, y2, pixelx); + if ((sseq->flag & SEQ_SHOW_STRIP_OVERLAY) && (sseq->flag & SEQ_SHOW_FCURVES)) { + draw_seq_fcurve_overlay(scene, v2d, seq, x1, y1, x2, y2, pixelx); } /* Draw sound strip waveform. */ - if ((seq->type == SEQ_TYPE_SOUND_RAM) && (sseq->flag & SEQ_NO_WAVEFORMS) == 0) { - draw_seq_waveform(v2d, - C, - sseq, - scene, - seq, - x1, - y_threshold ? y1 + 0.05f : y1, - x2, - y_threshold ? text_margin_y : y2, - BLI_rctf_size_x(®ion->v2d.cur) / region->winx); + if ((seq->type == SEQ_TYPE_SOUND_RAM) && ((sseq->flag & SEQ_SHOW_STRIP_OVERLAY)) && + (sseq->flag & SEQ_NO_WAVEFORMS) == 0) { + draw_seq_waveform_overlay(v2d, + C, + sseq, + scene, + seq, + x1, + y_threshold ? y1 + 0.05f : y1, + x2, + y_threshold ? text_margin_y : y2, + BLI_rctf_size_x(®ion->v2d.cur) / region->winx); } - /* Draw locked state. */ if (seq->flag & SEQ_LOCK) { draw_seq_locked(x1, y1, x2, y2); } /* Draw Red line on the top of invalid strip (Missing media). */ - if (!BKE_sequence_is_valid_check(seq)) { + if (!SEQ_sequence_has_source(seq)) { draw_seq_invalid(x1, x2, y2, text_margin_y); } @@ -1162,11 +1172,21 @@ static void draw_seq_strip(const bContext *C, calculate_seq_text_offsets(v2d, seq, &x1, &x2, pixelx); - /* Don't draw strip if there is not enough vertical or horizontal space. */ - if (((x2 - x1) > 32 * pixelx * U.dpi_fac) && ((y2 - y1) > 8 * pixely * U.dpi_fac)) { - /* Depending on the vertical space, draw text on top or in the center of strip. */ - draw_seq_text( - v2d, seq, sseq, x1, x2, y_threshold ? text_margin_y : y1, y2, seq_active, y_threshold); + /* If a waveform is drawn, avoid drawing text when there is not enough vertical space. */ + if (seq->type == SEQ_TYPE_SOUND_RAM) { + if (!y_threshold && (sseq->flag & SEQ_NO_WAVEFORMS) == 0 && + ((sseq->flag & SEQ_ALL_WAVEFORMS) || (seq->flag & SEQ_AUDIO_DRAW_WAVEFORM))) { + return; + } + } + + if (sseq->flag & SEQ_SHOW_STRIP_OVERLAY) { + /* Don't draw strip if there is not enough vertical or horizontal space. */ + if (((x2 - x1) > 32 * pixelx * U.dpi_fac) && ((y2 - y1) > 8 * pixely * U.dpi_fac)) { + /* Depending on the vertical space, draw text on top or in the center of strip. */ + draw_seq_text_overlay( + v2d, seq, sseq, x1, x2, y_threshold ? text_margin_y : y1, y2, seq_active); + } } } @@ -1360,7 +1380,7 @@ static void sequencer_display_size(Scene *scene, float r_viewrect[2]) r_viewrect[0] *= scene->r.xasp / scene->r.yasp; } -static void sequencer_draw_gpencil(const bContext *C) +static void sequencer_draw_gpencil_overlay(const bContext *C) { /* Draw grease-pencil (image aligned). */ ED_annotation_draw_2dimage(C); @@ -1373,7 +1393,9 @@ static void sequencer_draw_gpencil(const bContext *C) } /* Draw content and safety borders borders. */ -static void sequencer_draw_borders(const SpaceSeq *sseq, const View2D *v2d, const Scene *scene) +static void sequencer_draw_borders_overlay(const SpaceSeq *sseq, + const View2D *v2d, + const Scene *scene) { float x1 = v2d->tot.xmin; float y1 = v2d->tot.ymin; @@ -1428,7 +1450,7 @@ void sequencer_draw_maskedit(const bContext *C, Scene *scene, ARegion *region, S // if (sc->mode == SC_MODE_MASKEDIT) if (0 && sseq->mainb == SEQ_DRAW_IMG_IMBUF) { - Mask *mask = BKE_sequencer_mask_get(scene); + Mask *mask = SEQ_active_mask_get(scene); if (mask) { int width, height; @@ -1460,7 +1482,7 @@ void sequencer_draw_maskedit(const bContext *C, Scene *scene, ARegion *region, S /* Force redraw, when prefetching and using cache view. */ static void seq_prefetch_wm_notify(const bContext *C, Scene *scene) { - if (BKE_sequencer_prefetch_need_redraw(CTX_data_main(C), scene)) { + if (SEQ_prefetch_need_redraw(CTX_data_main(C), scene)) { WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, NULL); } } @@ -1825,17 +1847,17 @@ void sequencer_draw_preview(const bContext *C, C, scene, region, sseq, ibuf, scope, draw_overlay, draw_backdrop); /* Draw over image. */ - if (sseq->flag & SEQ_SHOW_METADATA) { + if (sseq->flag & SEQ_SHOW_METADATA && sseq->flag & SEQ_SHOW_STRIP_OVERLAY) { ED_region_image_metadata_draw(0.0, 0.0, ibuf, &v2d->tot, 1.0, 1.0); } } - if (show_imbuf) { - sequencer_draw_borders(sseq, v2d, scene); + if (show_imbuf && (sseq->flag & SEQ_SHOW_STRIP_OVERLAY)) { + sequencer_draw_borders_overlay(sseq, v2d, scene); } - if (draw_gpencil && show_imbuf) { - sequencer_draw_gpencil(C); + if (draw_gpencil && show_imbuf && (sseq->flag & SEQ_SHOW_STRIP_OVERLAY)) { + sequencer_draw_gpencil_overlay(C); } #if 0 sequencer_draw_maskedit(C, scene, region, sseq); @@ -1900,7 +1922,7 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region) Scene *scene = CTX_data_scene(C); View2D *v2d = ®ion->v2d; SpaceSeq *sseq = CTX_wm_space_seq(C); - Sequence *last_seq = BKE_sequencer_active_get(scene); + Sequence *last_seq = SEQ_select_active_get(scene); int sel = 0, j; float pixelx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask); @@ -1943,7 +1965,7 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region) draw_seq_strip(C, sseq, scene, region, last_seq, pixelx, true); /* When active strip is an effect, highlight its inputs. */ - if (BKE_sequence_effect_get_num_inputs(last_seq->type) > 0) { + if (SEQ_effect_get_num_inputs(last_seq->type) > 0) { draw_effect_inputs_highlight(last_seq); } /* When active is a Multi-cam strip, highlight its source channel. */ @@ -1987,7 +2009,7 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region) static void seq_draw_sfra_efra(Scene *scene, View2D *v2d) { - const Editing *ed = BKE_sequencer_editing_get(scene, false); + const Editing *ed = SEQ_editing_get(scene, false); const int frame_sta = scene->r.sfra; const int frame_end = scene->r.efra + 1; @@ -2089,8 +2111,10 @@ static bool draw_cache_view_init_fn(void *userdata, size_t item_count) } /* Called as a callback */ -static bool draw_cache_view_iter_fn( - void *userdata, struct Sequence *seq, int timeline_frame, int cache_type, float UNUSED(cost)) +static bool draw_cache_view_iter_fn(void *userdata, + struct Sequence *seq, + int timeline_frame, + int cache_type) { CacheDrawData *drawdata = userdata; struct View2D *v2d = drawdata->v2d; @@ -2252,7 +2276,7 @@ static void draw_cache_view(const bContext *C) userdata.composite_vbo = GPU_vertbuf_create_with_format(&format); userdata.final_out_vbo = GPU_vertbuf_create_with_format(&format); - BKE_sequencer_cache_iterate(scene, &userdata, draw_cache_view_init_fn, draw_cache_view_iter_fn); + SEQ_cache_iterate(scene, &userdata, draw_cache_view_init_fn, draw_cache_view_iter_fn); draw_cache_view_batch(userdata.raw_vbo, userdata.raw_vert_count, 1.0f, 0.1f, 0.02f, 0.4f); draw_cache_view_batch( @@ -2269,7 +2293,7 @@ static void draw_cache_view(const bContext *C) void draw_timeline_seq(const bContext *C, ARegion *region) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); SpaceSeq *sseq = CTX_wm_space_seq(C); View2D *v2d = ®ion->v2d; short cfra_flag = 0; @@ -2292,7 +2316,7 @@ void draw_timeline_seq(const bContext *C, ARegion *region) UI_view2d_view_ortho(v2d); /* Get timeline bound-box, needed for the scroll-bars. */ - boundbox_seq(scene, &v2d->tot); + SEQ_timeline_boundbox(scene, SEQ_active_seqbase_get(ed), &v2d->tot); draw_seq_backdrop(v2d); UI_view2d_constant_grid_draw(v2d, FPS); diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 93b17830c0f..c3553ac88ad 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -45,7 +45,19 @@ #include "BKE_report.h" #include "BKE_sound.h" +#include "SEQ_add.h" +#include "SEQ_clipboard.h" +#include "SEQ_edit.h" +#include "SEQ_effects.h" +#include "SEQ_iterator.h" +#include "SEQ_prefetch.h" +#include "SEQ_relations.h" +#include "SEQ_render.h" +#include "SEQ_select.h" #include "SEQ_sequencer.h" +#include "SEQ_time.h" +#include "SEQ_transform.h" +#include "SEQ_utils.h" #include "WM_api.h" #include "WM_types.h" @@ -96,7 +108,7 @@ bool ED_space_sequencer_maskedit_mask_poll(bContext *C) bool ED_space_sequencer_check_show_maskedit(SpaceSeq *sseq, Scene *scene) { if (sseq && sseq->mainb == SEQ_DRAW_IMG_IMBUF) { - return (BKE_sequencer_mask_get(scene) != NULL); + return (SEQ_active_mask_get(scene) != NULL); } return false; @@ -136,14 +148,14 @@ bool ED_space_sequencer_check_show_strip(SpaceSeq *sseq) /* Operator functions. */ bool sequencer_edit_poll(bContext *C) { - return (BKE_sequencer_editing_get(CTX_data_scene(C), false) != NULL); + return (SEQ_editing_get(CTX_data_scene(C), false) != NULL); } #if 0 /* UNUSED */ bool sequencer_strip_poll(bContext *C) { Editing *ed; - return (((ed = BKE_sequencer_editing_get(CTX_data_scene(C), false)) != NULL) && + return (((ed = SEQ_editing_get(CTX_data_scene(C), false)) != NULL) && (ed->act_seq != NULL)); } #endif @@ -152,14 +164,14 @@ bool sequencer_strip_has_path_poll(bContext *C) { Editing *ed; Sequence *seq; - return (((ed = BKE_sequencer_editing_get(CTX_data_scene(C), false)) != NULL) && + return (((ed = SEQ_editing_get(CTX_data_scene(C), false)) != NULL) && ((seq = ed->act_seq) != NULL) && (SEQ_HAS_PATH(seq))); } bool sequencer_view_preview_poll(bContext *C) { SpaceSeq *sseq = CTX_wm_space_seq(C); - Editing *ed = BKE_sequencer_editing_get(CTX_data_scene(C), false); + Editing *ed = SEQ_editing_get(CTX_data_scene(C), false); if (ed && sseq && (sseq->mainb == SEQ_DRAW_IMG_IMBUF)) { return 1; } @@ -183,117 +195,13 @@ bool sequencer_view_strips_poll(bContext *C) /** \name Remove Gaps Operator * \{ */ -static bool sequence_offset_after_frame(Scene *scene, const int delta, const int timeline_frame) -{ - Sequence *seq; - Editing *ed = BKE_sequencer_editing_get(scene, false); - bool done = false; - TimeMarker *marker; - - /* All strips >= timeline_frame are shifted. */ - - if (ed == NULL) { - return 0; - } - - for (seq = ed->seqbasep->first; seq; seq = seq->next) { - if (seq->startdisp >= timeline_frame) { - BKE_sequence_translate(scene, seq, delta); - BKE_sequence_calc(scene, seq); - BKE_sequence_invalidate_cache_preprocessed(scene, seq); - done = true; - } - } - - if (!scene->toolsettings->lock_markers) { - for (marker = scene->markers.first; marker; marker = marker->next) { - if (marker->frame >= timeline_frame) { - marker->frame += delta; - } - } - } - - return done; -} - -void boundbox_seq(Scene *scene, rctf *rect) -{ - Sequence *seq; - Editing *ed = BKE_sequencer_editing_get(scene, false); - float min[2], max[2]; - - if (ed == NULL) { - return; - } - - min[0] = SFRA; - max[0] = EFRA + 1; - min[1] = 0.0; - max[1] = 8.0; - - seq = ed->seqbasep->first; - while (seq) { - - if (min[0] > seq->startdisp - 1) { - min[0] = seq->startdisp - 1; - } - if (max[0] < seq->enddisp + 1) { - max[0] = seq->enddisp + 1; - } - if (max[1] < seq->machine + 2) { - max[1] = seq->machine + 2; - } - - seq = seq->next; - } - - rect->xmin = min[0]; - rect->xmax = max[0]; - rect->ymin = min[1]; - rect->ymax = max[1]; -} - static int sequencer_gap_remove_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - rctf rectf; - int timeline_frame, efra, sfra; - bool first = false, done; - bool do_all = RNA_boolean_get(op->ptr, "all"); - - /* Get first and last frame. */ - boundbox_seq(scene, &rectf); - sfra = (int)rectf.xmin; - efra = (int)rectf.xmax; - - /* Check if the current frame has a gap already. */ - for (timeline_frame = CFRA; timeline_frame >= sfra; timeline_frame--) { - if (SEQ_render_evaluate_frame(scene, timeline_frame)) { - first = true; - break; - } - } + const bool do_all = RNA_boolean_get(op->ptr, "all"); + const Editing *ed = SEQ_editing_get(scene, false); - for (; timeline_frame < efra; timeline_frame++) { - /* There's still no strip to remove a gap for. */ - if (first == false) { - if (SEQ_render_evaluate_frame(scene, timeline_frame)) { - first = true; - } - } - else if (SEQ_render_evaluate_frame(scene, timeline_frame) == 0) { - done = true; - while (SEQ_render_evaluate_frame(scene, timeline_frame) == 0) { - done = sequence_offset_after_frame(scene, -1, timeline_frame); - if (done == false) { - break; - } - } - if (done == false || do_all == false) { - break; - } - } - } + SEQ_edit_remove_gaps(scene, ed->seqbasep, CFRA, do_all); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); @@ -330,9 +238,9 @@ void SEQUENCER_OT_gap_remove(struct wmOperatorType *ot) static int sequencer_gap_insert_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - int frames = RNA_int_get(op->ptr, "frames"); - - sequence_offset_after_frame(scene, frames, CFRA); + const int frames = RNA_int_get(op->ptr, "frames"); + const Editing *ed = SEQ_editing_get(scene, false); + SEQ_transform_offset_after_frame(scene, ed->seqbasep, frames, CFRA); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -377,7 +285,7 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq; int snap_frame; @@ -386,22 +294,22 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op) /* Check metas. */ for (seq = ed->seqbasep->first; seq; seq = seq->next) { if (seq->flag & SELECT && !(seq->depth == 0 && seq->flag & SEQ_LOCK) && - BKE_sequence_tx_test(seq)) { + SEQ_transform_sequence_can_be_translated(seq)) { if ((seq->flag & (SEQ_LEFTSEL + SEQ_RIGHTSEL)) == 0) { - BKE_sequence_translate( + SEQ_transform_translate_sequence( scene, seq, (snap_frame - seq->startofs + seq->startstill) - seq->start); } else { if (seq->flag & SEQ_LEFTSEL) { - BKE_sequence_tx_set_final_left(seq, snap_frame); + SEQ_transform_set_left_handle_frame(seq, snap_frame); } else { /* SEQ_RIGHTSEL */ - BKE_sequence_tx_set_final_right(seq, snap_frame); + SEQ_transform_set_right_handle_frame(seq, snap_frame); } - BKE_sequence_tx_handle_xlimits(seq, seq->flag & SEQ_LEFTSEL, seq->flag & SEQ_RIGHTSEL); - BKE_sequence_single_fix(seq); + SEQ_transform_handle_xlimits(seq, seq->flag & SEQ_LEFTSEL, seq->flag & SEQ_RIGHTSEL); + SEQ_transform_fix_single_image_seq_offsets(seq); } - BKE_sequence_calc(scene, seq); + SEQ_time_update_sequence(scene, seq); } } @@ -410,8 +318,8 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op) for (seq = ed->seqbasep->first; seq; seq = seq->next) { if (seq->flag & SELECT && !(seq->depth == 0 && seq->flag & SEQ_LOCK)) { seq->flag &= ~SEQ_OVERLAP; - if (BKE_sequence_test_overlap(ed->seqbasep, seq)) { - BKE_sequence_base_shuffle(ed->seqbasep, seq, scene); + if (SEQ_transform_test_overlap(ed->seqbasep, seq)) { + SEQ_transform_seqbase_shuffle(ed->seqbasep, seq, scene); } } } @@ -420,21 +328,21 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op) for (seq = ed->seqbasep->first; seq; seq = seq->next) { if (seq->type & SEQ_TYPE_EFFECT) { if (seq->seq1 && (seq->seq1->flag & SELECT)) { - BKE_sequencer_offset_animdata(scene, seq, (snap_frame - seq->startdisp)); - BKE_sequence_calc(scene, seq); + SEQ_offset_animdata(scene, seq, (snap_frame - seq->startdisp)); + SEQ_time_update_sequence(scene, seq); } else if (seq->seq2 && (seq->seq2->flag & SELECT)) { - BKE_sequencer_offset_animdata(scene, seq, (snap_frame - seq->startdisp)); - BKE_sequence_calc(scene, seq); + SEQ_offset_animdata(scene, seq, (snap_frame - seq->startdisp)); + SEQ_time_update_sequence(scene, seq); } else if (seq->seq3 && (seq->seq3->flag & SELECT)) { - BKE_sequencer_offset_animdata(scene, seq, (snap_frame - seq->startdisp)); - BKE_sequence_calc(scene, seq); + SEQ_offset_animdata(scene, seq, (snap_frame - seq->startdisp)); + SEQ_time_update_sequence(scene, seq); } } } - BKE_sequencer_sort(scene); + SEQ_sort(scene); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -537,7 +445,7 @@ static int slip_add_sequences_recursive( for (seq = seqbasep->first; seq; seq = seq->next) { if (!do_trim || (!(seq->type & SEQ_TYPE_EFFECT) && (seq->flag & SELECT))) { seq_array[offset + num_items] = seq; - trim[offset + num_items] = do_trim; + trim[offset + num_items] = do_trim && ((seq->type & SEQ_TYPE_EFFECT) == 0); num_items++; if (seq->type == SEQ_TYPE_META) { @@ -545,9 +453,6 @@ static int slip_add_sequences_recursive( num_items += slip_add_sequences_recursive( &seq->seqbase, seq_array, trim, num_items + offset, false); } - else if (seq->type & SEQ_TYPE_EFFECT) { - trim[offset + num_items] = false; - } } } @@ -577,7 +482,7 @@ static int sequencer_slip_invoke(bContext *C, wmOperator *op, const wmEvent *eve { SlipData *data; Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); float mouseloc[2]; int num_seq; View2D *v2d = UI_view2d_fromcontext(C); @@ -625,7 +530,7 @@ static int sequencer_slip_invoke(bContext *C, wmOperator *op, const wmEvent *eve static bool sequencer_slip_recursively(Scene *scene, SlipData *data, int offset) { /* Only data types supported for now. */ - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); bool changed = false; /* Iterate in reverse so meta-strips are iterated after their children. */ @@ -675,11 +580,11 @@ static bool sequencer_slip_recursively(Scene *scene, SlipData *data, int offset) * we can skip calculating for effects. * This way we can avoid an extra loop just for effects. */ if (!(seq->type & SEQ_TYPE_EFFECT)) { - BKE_sequence_calc(scene, seq); + SEQ_time_update_sequence(scene, seq); } } if (changed) { - BKE_sequencer_free_imbuf(scene, &ed->seqbase, false); + SEQ_relations_free_imbuf(scene, &ed->seqbase, false); } return changed; } @@ -709,7 +614,7 @@ static void sequencer_slip_apply_limits(SlipData *data, int *offset) static int sequencer_slip_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); int offset = RNA_int_get(op->ptr, "offset"); bool success = false; @@ -844,7 +749,7 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even case EVT_ESCKEY: case RIGHTMOUSE: { - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); for (int i = 0; i < data->num_seq; i++) { transseq_restore(data->ts + i, data->seq_array[i]); @@ -852,8 +757,8 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even for (int i = 0; i < data->num_seq; i++) { Sequence *seq = data->seq_array[i]; - BKE_sequence_reload_new_file(bmain, scene, seq, false); - BKE_sequence_calc(scene, seq); + SEQ_add_reload_new_file(bmain, scene, seq, false); + SEQ_time_update_sequence(scene, seq); } MEM_freeN(data->seq_array); @@ -864,7 +769,7 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); - BKE_sequencer_free_imbuf(scene, &ed->seqbase, false); + SEQ_relations_free_imbuf(scene, &ed->seqbase, false); if (area) { ED_area_status_text(area, NULL); @@ -946,7 +851,7 @@ void SEQUENCER_OT_slip(struct wmOperatorType *ot) static int sequencer_mute_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq; bool selected; @@ -957,13 +862,13 @@ static int sequencer_mute_exec(bContext *C, wmOperator *op) if (selected) { if (seq->flag & SELECT) { seq->flag |= SEQ_MUTE; - BKE_sequence_invalidate_dependent(scene, seq); + SEQ_relations_invalidate_dependent(scene, seq); } } else { if ((seq->flag & SELECT) == 0) { seq->flag |= SEQ_MUTE; - BKE_sequence_invalidate_dependent(scene, seq); + SEQ_relations_invalidate_dependent(scene, seq); } } } @@ -1002,7 +907,7 @@ void SEQUENCER_OT_mute(struct wmOperatorType *ot) static int sequencer_unmute_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq; bool selected; @@ -1013,13 +918,13 @@ static int sequencer_unmute_exec(bContext *C, wmOperator *op) if (selected) { if (seq->flag & SELECT) { seq->flag &= ~SEQ_MUTE; - BKE_sequence_invalidate_dependent(scene, seq); + SEQ_relations_invalidate_dependent(scene, seq); } } else { if ((seq->flag & SELECT) == 0) { seq->flag &= ~SEQ_MUTE; - BKE_sequence_invalidate_dependent(scene, seq); + SEQ_relations_invalidate_dependent(scene, seq); } } } @@ -1058,7 +963,7 @@ void SEQUENCER_OT_unmute(struct wmOperatorType *ot) static int sequencer_lock_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq; for (seq = ed->seqbasep->first; seq; seq = seq->next) { @@ -1096,7 +1001,7 @@ void SEQUENCER_OT_lock(struct wmOperatorType *ot) static int sequencer_unlock_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq; for (seq = ed->seqbasep->first; seq; seq = seq->next) { @@ -1135,18 +1040,18 @@ static int sequencer_reload_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq; const bool adjust_length = RNA_boolean_get(op->ptr, "adjust_length"); for (seq = ed->seqbasep->first; seq; seq = seq->next) { if (seq->flag & SELECT) { - BKE_sequencer_update_changed_seq_and_deps(scene, seq, 0, 1); - BKE_sequence_reload_new_file(bmain, scene, seq, !adjust_length); + SEQ_relations_update_changed_seq_and_deps(scene, seq, 0, 1); + SEQ_add_reload_new_file(bmain, scene, seq, !adjust_length); if (adjust_length) { - if (BKE_sequence_test_overlap(ed->seqbasep, seq)) { - BKE_sequence_base_shuffle(ed->seqbasep, seq, scene); + if (SEQ_transform_test_overlap(ed->seqbasep, seq)) { + SEQ_transform_seqbase_shuffle(ed->seqbasep, seq, scene); } } } @@ -1198,9 +1103,9 @@ static bool sequencer_refresh_all_poll(bContext *C) static int sequencer_refresh_all_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); - BKE_sequencer_free_imbuf(scene, &ed->seqbase, false); + SEQ_relations_free_imbuf(scene, &ed->seqbase, false); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -1233,18 +1138,18 @@ int seq_effect_find_selected(Scene *scene, Sequence **r_selseq3, const char **r_error_str) { - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq1 = NULL, *seq2 = NULL, *seq3 = NULL, *seq; *r_error_str = NULL; if (!activeseq) { - seq2 = BKE_sequencer_active_get(scene); + seq2 = SEQ_select_active_get(scene); } for (seq = ed->seqbasep->first; seq; seq = seq->next) { if (seq->flag & SELECT) { - if (seq->type == SEQ_TYPE_SOUND_RAM && BKE_sequence_effect_get_num_inputs(type) != 0) { + if (seq->type == SEQ_TYPE_SOUND_RAM && SEQ_effect_get_num_inputs(type) != 0) { *r_error_str = N_("Cannot apply effects to audio sequence strips"); return 0; } @@ -1274,7 +1179,7 @@ int seq_effect_find_selected(Scene *scene, seq3 = tmp; } - switch (BKE_sequence_effect_get_num_inputs(type)) { + switch (SEQ_effect_get_num_inputs(type)) { case 0: *r_selseq1 = *r_selseq2 = *r_selseq3 = NULL; return 1; /* Success. */ @@ -1311,10 +1216,10 @@ int seq_effect_find_selected(Scene *scene, *r_selseq3 = seq3; /* TODO(Richard): This function needs some refactoring, this is just quick hack for T73828. */ - if (BKE_sequence_effect_get_num_inputs(type) < 3) { + if (SEQ_effect_get_num_inputs(type) < 3) { *r_selseq3 = NULL; } - if (BKE_sequence_effect_get_num_inputs(type) < 2) { + if (SEQ_effect_get_num_inputs(type) < 2) { *r_selseq2 = NULL; } @@ -1324,24 +1229,24 @@ int seq_effect_find_selected(Scene *scene, static int sequencer_reassign_inputs_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Sequence *seq1, *seq2, *seq3, *last_seq = BKE_sequencer_active_get(scene); + Sequence *seq1, *seq2, *seq3, *last_seq = SEQ_select_active_get(scene); const char *error_msg; - if (BKE_sequence_effect_get_num_inputs(last_seq->type) == 0) { + if (SEQ_effect_get_num_inputs(last_seq->type) == 0) { BKE_report(op->reports, RPT_ERROR, "Cannot reassign inputs: strip has no inputs"); return OPERATOR_CANCELLED; } if (!seq_effect_find_selected( scene, last_seq, last_seq->type, &seq1, &seq2, &seq3, &error_msg) || - BKE_sequence_effect_get_num_inputs(last_seq->type) == 0) { + SEQ_effect_get_num_inputs(last_seq->type) == 0) { BKE_report(op->reports, RPT_ERROR, error_msg); return OPERATOR_CANCELLED; } /* Check if reassigning would create recursivity. */ - if (BKE_sequencer_render_loop_check(seq1, last_seq) || - BKE_sequencer_render_loop_check(seq2, last_seq) || - BKE_sequencer_render_loop_check(seq3, last_seq)) { + if (SEQ_relations_render_loop_check(seq1, last_seq) || + SEQ_relations_render_loop_check(seq2, last_seq) || + SEQ_relations_render_loop_check(seq3, last_seq)) { BKE_report(op->reports, RPT_ERROR, "Cannot reassign inputs: recursion detected"); return OPERATOR_CANCELLED; } @@ -1350,7 +1255,7 @@ static int sequencer_reassign_inputs_exec(bContext *C, wmOperator *op) last_seq->seq2 = seq2; last_seq->seq3 = seq3; - BKE_sequencer_update_changed_seq_and_deps(scene, last_seq, 1, 1); + SEQ_relations_update_changed_seq_and_deps(scene, last_seq, 1, 1); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -1360,10 +1265,10 @@ static int sequencer_reassign_inputs_exec(bContext *C, wmOperator *op) static bool sequencer_effect_poll(bContext *C) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (ed) { - Sequence *last_seq = BKE_sequencer_active_get(scene); + Sequence *last_seq = SEQ_select_active_get(scene); if (last_seq && (last_seq->type & SEQ_TYPE_EFFECT)) { return 1; } @@ -1396,7 +1301,7 @@ void SEQUENCER_OT_reassign_inputs(struct wmOperatorType *ot) static int sequencer_swap_inputs_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Sequence *seq, *last_seq = BKE_sequencer_active_get(scene); + Sequence *seq, *last_seq = SEQ_select_active_get(scene); if (last_seq->seq1 == NULL || last_seq->seq2 == NULL) { BKE_report(op->reports, RPT_ERROR, "No valid inputs to swap"); @@ -1407,7 +1312,7 @@ static int sequencer_swap_inputs_exec(bContext *C, wmOperator *op) last_seq->seq1 = last_seq->seq2; last_seq->seq2 = seq; - BKE_sequencer_update_changed_seq_and_deps(scene, last_seq, 1, 1); + SEQ_relations_update_changed_seq_and_deps(scene, last_seq, 1, 1); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -1467,7 +1372,7 @@ static int sequencer_split_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); bool changed = false; bool seq_selected = false; @@ -1478,7 +1383,7 @@ static int sequencer_split_exec(bContext *C, wmOperator *op) const int split_side = RNA_enum_get(op->ptr, "side"); const bool ignore_selection = RNA_boolean_get(op->ptr, "ignore_selection"); - BKE_sequencer_prefetch_stop(scene); + SEQ_prefetch_stop(scene); LISTBASE_FOREACH_BACKWARD (Sequence *, seq, ed->seqbasep) { if (use_cursor_position && seq->machine != split_channel) { @@ -1530,7 +1435,7 @@ static int sequencer_split_exec(bContext *C, wmOperator *op) } } - BKE_sequencer_sort(scene); + SEQ_sort(scene); } if (changed) { WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -1673,15 +1578,15 @@ static int apply_unique_name_fn(Sequence *seq, void *arg_pt) char name[sizeof(seq->name) - 2]; BLI_strncpy_utf8(name, seq->name + 2, sizeof(name)); - BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq); - BKE_sequencer_dupe_animdata(scene, name, seq->name + 2); + SEQ_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq); + SEQ_dupe_animdata(scene, name, seq->name + 2); return 1; } static int sequencer_add_duplicate_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); ListBase nseqbase = {NULL, NULL}; @@ -1689,16 +1594,16 @@ static int sequencer_add_duplicate_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_CANCELLED; } - BKE_sequence_base_dupli_recursive(scene, scene, &nseqbase, ed->seqbasep, SEQ_DUPE_CONTEXT, 0); + SEQ_sequence_base_dupli_recursive(scene, scene, &nseqbase, ed->seqbasep, SEQ_DUPE_CONTEXT, 0); if (nseqbase.first) { Sequence *seq = nseqbase.first; /* Rely on the nseqbase list being added at the end. - * Their UUIDs has been re-generated by the BKE_sequence_base_dupli_recursive(), */ + * Their UUIDs has been re-generated by the SEQ_sequence_base_dupli_recursive(), */ BLI_movelisttolist(ed->seqbasep, &nseqbase); for (; seq; seq = seq->next) { - BKE_sequencer_recursive_apply(seq, apply_unique_name_fn, scene); + SEQ_iterator_recursive_apply(seq, apply_unique_name_fn, scene); } WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -1733,18 +1638,18 @@ static int sequencer_delete_exec(bContext *C, wmOperator *UNUSED(op)) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq; - BKE_sequencer_prefetch_stop(scene); + SEQ_prefetch_stop(scene); SEQ_CURRENT_BEGIN (scene->ed, seq) { if (seq->flag & SELECT) { - BKE_sequencer_flag_for_removal(scene, ed->seqbasep, seq); + SEQ_edit_flag_for_removal(scene, ed->seqbasep, seq); } } SEQ_CURRENT_END; - BKE_sequencer_remove_flagged_sequences(scene, ed->seqbasep); + SEQ_edit_remove_flagged_sequences(scene, ed->seqbasep); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); DEG_relations_tag_update(bmain); @@ -1794,7 +1699,7 @@ void SEQUENCER_OT_delete(wmOperatorType *ot) static int sequencer_offset_clear_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq; /* For effects, try to find a replacement input. */ @@ -1807,14 +1712,14 @@ static int sequencer_offset_clear_exec(bContext *C, wmOperator *UNUSED(op)) /* Update lengths, etc. */ seq = ed->seqbasep->first; while (seq) { - BKE_sequence_calc(scene, seq); + SEQ_time_update_sequence(scene, seq); seq = seq->next; } for (seq = ed->seqbasep->first; seq; seq = seq->next) { if ((seq->type & SEQ_TYPE_EFFECT) == 0 && (seq->flag & SELECT)) { - if (BKE_sequence_test_overlap(ed->seqbasep, seq)) { - BKE_sequence_base_shuffle(ed->seqbasep, seq, scene); + if (SEQ_transform_test_overlap(ed->seqbasep, seq)) { + SEQ_transform_seqbase_shuffle(ed->seqbasep, seq, scene); } } } @@ -1849,7 +1754,7 @@ void SEQUENCER_OT_offset_clear(wmOperatorType *ot) static int sequencer_separate_images_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq, *seq_new; Strip *strip_new; @@ -1859,7 +1764,7 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op) seq = ed->seqbasep->first; /* Poll checks this is valid. */ - BKE_sequencer_prefetch_stop(scene); + SEQ_prefetch_stop(scene); while (seq) { if ((seq->flag & SELECT) && (seq->type == SEQ_TYPE_IMAGE) && (seq->len > 1)) { @@ -1871,14 +1776,14 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op) /* if (seq->ipo) id_us_min(&seq->ipo->id); */ /* XXX, remove fcurve and assign to split image strips */ - start_ofs = timeline_frame = BKE_sequence_tx_get_final_left(seq, false); - frame_end = BKE_sequence_tx_get_final_right(seq, false); + start_ofs = timeline_frame = SEQ_transform_get_left_handle_frame(seq, false); + frame_end = SEQ_transform_get_right_handle_frame(seq, false); while (timeline_frame < frame_end) { /* New seq. */ se = SEQ_render_give_stripelem(seq, timeline_frame); - seq_new = BKE_sequence_dupli_recursive( + seq_new = SEQ_sequence_dupli_recursive( scene, scene, ed->seqbasep, seq, SEQ_DUPE_UNIQUE_NAME); seq_new->start = start_ofs; @@ -1897,12 +1802,12 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op) BLI_strncpy(se_new->name, se->name, sizeof(se_new->name)); strip_new->stripdata = se_new; - BKE_sequence_calc(scene, seq_new); + SEQ_time_update_sequence(scene, seq_new); if (step > 1) { seq_new->flag &= ~SEQ_OVERLAP; - if (BKE_sequence_test_overlap(ed->seqbasep, seq_new)) { - BKE_sequence_base_shuffle(ed->seqbasep, seq_new, scene); + if (SEQ_transform_test_overlap(ed->seqbasep, seq_new)) { + SEQ_transform_seqbase_shuffle(ed->seqbasep, seq_new, scene); } } @@ -1913,7 +1818,7 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op) } seq_next = seq->next; - BKE_sequence_free(scene, seq, true); + SEQ_sequence_free(scene, seq, true); seq = seq_next; } else { @@ -1921,7 +1826,7 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op) } } - BKE_sequencer_sort(scene); + SEQ_sort(scene); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -1980,8 +1885,8 @@ void recurs_sel_seq(Sequence *seqm) static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); - Sequence *last_seq = BKE_sequencer_active_get(scene); + Editing *ed = SEQ_editing_get(scene, false); + Sequence *last_seq = SEQ_select_active_get(scene); MetaStack *ms; if (last_seq && last_seq->type == SEQ_TYPE_META && last_seq->flag & SELECT) { @@ -1994,7 +1899,7 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op)) ed->seqbasep = &last_seq->seqbase; - BKE_sequencer_active_set(scene, NULL); + SEQ_select_active_set(scene, NULL); } else { /* Exit metastrip if possible. */ @@ -2017,23 +1922,23 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op)) /* Recalc all: the meta can have effects connected to it. */ for (seq = ed->seqbasep->first; seq; seq = seq->next) { - BKE_sequence_calc(scene, seq); + SEQ_time_update_sequence(scene, seq); } /* 2.73+, keeping endpoints is important! * Moving them around means you can't usefully use metas in a complex edit. */ #if 1 - BKE_sequence_tx_set_final_left(ms->parseq, ms->disp_range[0]); - BKE_sequence_tx_set_final_right(ms->parseq, ms->disp_range[1]); - BKE_sequence_single_fix(ms->parseq); - BKE_sequence_calc(scene, ms->parseq); + SEQ_transform_set_left_handle_frame(ms->parseq, ms->disp_range[0]); + SEQ_transform_set_right_handle_frame(ms->parseq, ms->disp_range[1]); + SEQ_transform_fix_single_image_seq_offsets(ms->parseq); + SEQ_time_update_sequence(scene, ms->parseq); #else - if (BKE_sequence_test_overlap(ed->seqbasep, ms->parseq)) { - BKE_sequence_base_shuffle(ed->seqbasep, ms->parseq, scene); + if (SEQ_transform_test_overlap(ed->seqbasep, ms->parseq)) { + SEQ_transform_seqbase_shuffle(ed->seqbasep, ms->parseq, scene); } #endif - BKE_sequencer_active_set(scene, ms->parseq); + SEQ_select_active_set(scene, ms->parseq); ms->parseq->flag |= SELECT; recurs_sel_seq(ms->parseq); @@ -2071,21 +1976,21 @@ void SEQUENCER_OT_meta_toggle(wmOperatorType *ot) static int sequencer_meta_make_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); - Sequence *seq, *seqm, *next, *last_seq = BKE_sequencer_active_get(scene); + Sequence *seq, *seqm, *next, *last_seq = SEQ_select_active_get(scene); int channel_max = 1; - if (BKE_sequence_base_isolated_sel_check(ed->seqbasep) == false) { + if (SEQ_transform_seqbase_isolated_sel_check(ed->seqbasep) == false) { BKE_report(op->reports, RPT_ERROR, "Please select all related strips"); return OPERATOR_CANCELLED; } - BKE_sequencer_prefetch_stop(scene); + SEQ_prefetch_stop(scene); /* Remove all selected from main list, and put in meta. */ - seqm = BKE_sequence_alloc(ed->seqbasep, 1, 1, SEQ_TYPE_META); /* Channel number set later. */ + seqm = SEQ_sequence_alloc(ed->seqbasep, 1, 1, SEQ_TYPE_META); /* Channel number set later. */ strcpy(seqm->name + 2, "MetaStrip"); seqm->flag = SELECT; @@ -2093,7 +1998,7 @@ static int sequencer_meta_make_exec(bContext *C, wmOperator *op) while (seq) { next = seq->next; if (seq != seqm && (seq->flag & SELECT)) { - BKE_sequence_invalidate_cache_composite(scene, seq); + SEQ_relations_invalidate_cache_composite(scene, seq); channel_max = max_ii(seq->machine, channel_max); /* Sequence is moved within the same edit, no need to re-generate the UUID. */ BLI_remlink(ed->seqbasep, seq); @@ -2102,18 +2007,18 @@ static int sequencer_meta_make_exec(bContext *C, wmOperator *op) seq = next; } seqm->machine = last_seq ? last_seq->machine : channel_max; - BKE_sequence_calc(scene, seqm); + SEQ_time_update_sequence(scene, seqm); - BKE_sequencer_active_set(scene, seqm); + SEQ_select_active_set(scene, seqm); - if (BKE_sequence_test_overlap(ed->seqbasep, seqm)) { - BKE_sequence_base_shuffle(ed->seqbasep, seqm, scene); + if (SEQ_transform_test_overlap(ed->seqbasep, seqm)) { + SEQ_transform_seqbase_shuffle(ed->seqbasep, seqm, scene); } DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); - BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seqm); - BKE_sequence_invalidate_cache_composite(scene, seqm); + SEQ_sequence_base_unique_name_recursive(&scene->ed->seqbase, seqm); + SEQ_relations_invalidate_cache_composite(scene, seqm); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); return OPERATOR_FINISHED; @@ -2160,7 +2065,7 @@ static int seq_depends_on_meta(Sequence *seq, Sequence *seqm) static void recurs_del_seq_flag(Scene *scene, ListBase *lb, short flag, short deleteall) { Sequence *seq, *seqn; - Sequence *last_seq = BKE_sequencer_active_get(scene); + Sequence *last_seq = SEQ_select_active_get(scene); seq = lb->first; while (seq) { @@ -2168,12 +2073,12 @@ static void recurs_del_seq_flag(Scene *scene, ListBase *lb, short flag, short de if ((seq->flag & flag) || deleteall) { BLI_remlink(lb, seq); if (seq == last_seq) { - BKE_sequencer_active_set(scene, NULL); + SEQ_select_active_set(scene, NULL); } if (seq->type == SEQ_TYPE_META) { recurs_del_seq_flag(scene, &seq->seqbase, flag, 1); } - BKE_sequence_free(scene, seq, true); + SEQ_sequence_free(scene, seq, true); } seq = seqn; } @@ -2182,18 +2087,18 @@ static void recurs_del_seq_flag(Scene *scene, ListBase *lb, short flag, short de static int sequencer_meta_separate_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); - Sequence *seq, *last_seq = BKE_sequencer_active_get(scene); /* last_seq checks (ed == NULL) */ + Sequence *seq, *last_seq = SEQ_select_active_get(scene); /* last_seq checks (ed == NULL) */ if (last_seq == NULL || last_seq->type != SEQ_TYPE_META) { return OPERATOR_CANCELLED; } - BKE_sequencer_prefetch_stop(scene); + SEQ_prefetch_stop(scene); for (seq = last_seq->seqbase.first; seq != NULL; seq = seq->next) { - BKE_sequence_invalidate_cache_composite(scene, seq); + SEQ_relations_invalidate_cache_composite(scene, seq); } /* This moves strips from meta to parent, sating within same edit and no new strips are @@ -2204,7 +2109,7 @@ static int sequencer_meta_separate_exec(bContext *C, wmOperator *UNUSED(op)) BLI_listbase_clear(&last_seq->seqbase); BLI_remlink(ed->seqbasep, last_seq); - BKE_sequence_free(scene, last_seq, true); + SEQ_sequence_free(scene, last_seq, true); /* Empty meta strip, delete all effects depending on it. */ for (seq = ed->seqbasep->first; seq; seq = seq->next) { @@ -2220,13 +2125,13 @@ static int sequencer_meta_separate_exec(bContext *C, wmOperator *UNUSED(op)) for (seq = ed->seqbasep->first; seq; seq = seq->next) { if (seq->flag & SELECT) { seq->flag &= ~SEQ_OVERLAP; - if (BKE_sequence_test_overlap(ed->seqbasep, seq)) { - BKE_sequence_base_shuffle(ed->seqbasep, seq, scene); + if (SEQ_transform_test_overlap(ed->seqbasep, seq)) { + SEQ_transform_seqbase_shuffle(ed->seqbasep, seq, scene); } } } - BKE_sequencer_sort(scene); + SEQ_sort(scene); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -2262,7 +2167,7 @@ static bool strip_jump_internal(Scene *scene, { bool changed = false; int timeline_frame = CFRA; - int next_frame = BKE_sequencer_find_next_prev_edit( + int next_frame = SEQ_time_find_next_prev_edit( scene, timeline_frame, side, do_skip_mute, do_center, false); if (next_frame != timeline_frame) { @@ -2337,19 +2242,19 @@ static void swap_sequence(Scene *scene, Sequence *seqa, Sequence *seqb) int seq_b_start; seq_b_start = (seqb->start - seqb->startdisp) + seqa->startdisp; - BKE_sequence_translate(scene, seqb, seq_b_start - seqb->start); - BKE_sequence_calc(scene, seqb); + SEQ_transform_translate_sequence(scene, seqb, seq_b_start - seqb->start); + SEQ_time_update_sequence(scene, seqb); seq_a_start = (seqa->start - seqa->startdisp) + seqb->enddisp + gap; - BKE_sequence_translate(scene, seqa, seq_a_start - seqa->start); - BKE_sequence_calc(scene, seqa); + SEQ_transform_translate_sequence(scene, seqa, seq_a_start - seqa->start); + SEQ_time_update_sequence(scene, seqa); } static Sequence *find_next_prev_sequence(Scene *scene, Sequence *test, int lr, int sel) { /* sel: 0==unselected, 1==selected, -1==don't care. */ Sequence *seq, *best_seq = NULL; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); int dist, best_dist; best_dist = MAXFRAME * 2; @@ -2399,8 +2304,8 @@ static bool seq_is_parent(Sequence *par, Sequence *seq) static int sequencer_swap_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); - Sequence *active_seq = BKE_sequencer_active_get(scene); + Editing *ed = SEQ_editing_get(scene, false); + Sequence *active_seq = SEQ_select_active_get(scene); Sequence *seq, *iseq; int side = RNA_enum_get(op->ptr, "side"); @@ -2413,11 +2318,11 @@ static int sequencer_swap_exec(bContext *C, wmOperator *op) if (seq) { /* Disallow effect strips. */ - if (BKE_sequence_effect_get_num_inputs(seq->type) >= 1 && + if (SEQ_effect_get_num_inputs(seq->type) >= 1 && (seq->effectdata || seq->seq1 || seq->seq2 || seq->seq3)) { return OPERATOR_CANCELLED; } - if ((BKE_sequence_effect_get_num_inputs(active_seq->type) >= 1) && + if ((SEQ_effect_get_num_inputs(active_seq->type) >= 1) && (active_seq->effectdata || active_seq->seq1 || active_seq->seq2 || active_seq->seq3)) { return OPERATOR_CANCELLED; } @@ -2435,7 +2340,7 @@ static int sequencer_swap_exec(bContext *C, wmOperator *op) for (iseq = scene->ed->seqbasep->first; iseq; iseq = iseq->next) { if ((iseq->type & SEQ_TYPE_EFFECT) && (seq_is_parent(iseq, active_seq) || seq_is_parent(iseq, seq))) { - BKE_sequence_calc(scene, iseq); + SEQ_time_update_sequence(scene, iseq); } } @@ -2444,13 +2349,13 @@ static int sequencer_swap_exec(bContext *C, wmOperator *op) if ((iseq->type & SEQ_TYPE_EFFECT) && (seq_is_parent(iseq, active_seq) || seq_is_parent(iseq, seq))) { /* This may now overlap. */ - if (BKE_sequence_test_overlap(ed->seqbasep, iseq)) { - BKE_sequence_base_shuffle(ed->seqbasep, iseq, scene); + if (SEQ_transform_test_overlap(ed->seqbasep, iseq)) { + SEQ_transform_seqbase_shuffle(ed->seqbasep, iseq, scene); } } } - BKE_sequencer_sort(scene); + SEQ_sort(scene); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -2489,7 +2394,7 @@ static int sequencer_rendersize_exec(bContext *C, wmOperator *UNUSED(op)) { int retval = OPERATOR_CANCELLED; Scene *scene = CTX_data_scene(C); - Sequence *active_seq = BKE_sequencer_active_get(scene); + Sequence *active_seq = SEQ_select_active_get(scene); StripElem *se = NULL; if (active_seq == NULL) { @@ -2565,11 +2470,11 @@ static int sequencer_copy_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); - BKE_sequencer_free_clipboard(); + SEQ_clipboard_free(); - if (BKE_sequence_base_isolated_sel_check(ed->seqbasep) == false) { + if (SEQ_transform_seqbase_isolated_sel_check(ed->seqbasep) == false) { BKE_report(op->reports, RPT_ERROR, "Please select all related strips"); return OPERATOR_CANCELLED; } @@ -2577,7 +2482,7 @@ static int sequencer_copy_exec(bContext *C, wmOperator *op) /* NOTE: The UUID is re-generated on paste, so we can keep UUID in the clipboard since * nobody can reach them anyway. * This reduces chance or running out of UUIDs if a cat falls asleep on Ctrl-C. */ - BKE_sequence_base_dupli_recursive(scene, + SEQ_sequence_base_dupli_recursive(scene, scene, &seqbase_clipboard, ed->seqbasep, @@ -2593,7 +2498,7 @@ static int sequencer_copy_exec(bContext *C, wmOperator *op) /* Replace datablock pointers with copies, to keep things working in case * data-blocks get deleted or another .blend file is opened. */ - BKE_sequencer_base_clipboard_pointers_store(bmain, &seqbase_clipboard); + SEQ_clipboard_pointers_store(bmain, &seqbase_clipboard); return OPERATOR_FINISHED; } @@ -2622,7 +2527,7 @@ void SEQUENCER_OT_copy(wmOperatorType *ot) void ED_sequencer_deselect_all(Scene *scene) { Sequence *seq; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (ed == NULL) { return; @@ -2634,40 +2539,57 @@ void ED_sequencer_deselect_all(Scene *scene) SEQ_CURRENT_END; } -static int sequencer_paste_exec(bContext *C, wmOperator *UNUSED(op)) +static int sequencer_paste_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, true); /* Create if needed. */ + Editing *ed = SEQ_editing_get(scene, true); /* Create if needed. */ ListBase nseqbase = {NULL, NULL}; int ofs; Sequence *iseq, *iseq_first; + if (BLI_listbase_count(&seqbase_clipboard) == 0) { + BKE_report(op->reports, RPT_INFO, "No strips to paste"); + return OPERATOR_CANCELLED; + } + ED_sequencer_deselect_all(scene); - ofs = scene->r.cfra - seqbase_clipboard_frame; + if (RNA_boolean_get(op->ptr, "keep_offset")) { + ofs = scene->r.cfra - seqbase_clipboard_frame; + } + else { + int min_seq_startdisp = INT_MAX; + LISTBASE_FOREACH (Sequence *, seq, &seqbase_clipboard) { + if (seq->startdisp < min_seq_startdisp) { + min_seq_startdisp = seq->startdisp; + } + } + /* Paste strips after playhead. */ + ofs = scene->r.cfra - min_seq_startdisp; + } /* Copy strips, temporarily restoring pointers to actual data-blocks. This * must happen on the clipboard itself, so that copying does user counting * on the actual data-blocks. */ - BKE_sequencer_base_clipboard_pointers_restore(&seqbase_clipboard, bmain); - BKE_sequence_base_dupli_recursive(scene, scene, &nseqbase, &seqbase_clipboard, 0, 0); - BKE_sequencer_base_clipboard_pointers_store(bmain, &seqbase_clipboard); + SEQ_clipboard_pointers_restore(&seqbase_clipboard, bmain); + SEQ_sequence_base_dupli_recursive(scene, scene, &nseqbase, &seqbase_clipboard, 0, 0); + SEQ_clipboard_pointers_store(bmain, &seqbase_clipboard); iseq_first = nseqbase.first; - /* NOTE: BKE_sequence_base_dupli_recursive() takes care of generating new UUIDs for sequences + /* NOTE: SEQ_sequence_base_dupli_recursive() takes care of generating new UUIDs for sequences * in the new list. */ BLI_movelisttolist(ed->seqbasep, &nseqbase); for (iseq = iseq_first; iseq; iseq = iseq->next) { /* Make sure, that pasted strips have unique names. */ - BKE_sequencer_recursive_apply(iseq, apply_unique_name_fn, scene); + SEQ_iterator_recursive_apply(iseq, apply_unique_name_fn, scene); /* Translate after name has been changed, otherwise this will affect animdata of original * strip. */ - BKE_sequence_translate(scene, iseq, ofs); + SEQ_transform_translate_sequence(scene, iseq, ofs); /* Ensure, that pasted strips don't overlap. */ - if (BKE_sequence_test_overlap(ed->seqbasep, iseq)) { - BKE_sequence_base_shuffle(ed->seqbasep, iseq, scene); + if (SEQ_transform_test_overlap(ed->seqbasep, iseq)) { + SEQ_transform_seqbase_shuffle(ed->seqbasep, iseq, scene); } } @@ -2692,6 +2614,11 @@ void SEQUENCER_OT_paste(wmOperatorType *ot) /* Flags. */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* Properties. */ + PropertyRNA *prop = RNA_def_boolean( + ot->srna, "keep_offset", false, "Keep Offset", "Keep strip offset to playhead when pasting"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /** \} */ @@ -2707,12 +2634,12 @@ static int sequencer_swap_data_exec(bContext *C, wmOperator *op) Sequence *seq_other; const char *error_msg; - if (BKE_sequencer_active_get_pair(scene, &seq_act, &seq_other) == 0) { + if (SEQ_select_active_get_pair(scene, &seq_act, &seq_other) == 0) { BKE_report(op->reports, RPT_ERROR, "Please select two strips"); return OPERATOR_CANCELLED; } - if (BKE_sequence_swap(seq_act, seq_other, &error_msg) == 0) { + if (SEQ_edit_sequence_swap(seq_act, seq_other, &error_msg) == 0) { BKE_report(op->reports, RPT_ERROR, error_msg); return OPERATOR_CANCELLED; } @@ -2728,8 +2655,8 @@ static int sequencer_swap_data_exec(bContext *C, wmOperator *op) seq_act->scene_sound = NULL; seq_other->scene_sound = NULL; - BKE_sequence_calc(scene, seq_act); - BKE_sequence_calc(scene, seq_other); + SEQ_time_update_sequence(scene, seq_act); + SEQ_time_update_sequence(scene, seq_other); if (seq_act->sound) { BKE_sound_add_scene_sound_defaults(scene, seq_act); @@ -2738,8 +2665,8 @@ static int sequencer_swap_data_exec(bContext *C, wmOperator *op) BKE_sound_add_scene_sound_defaults(scene, seq_other); } - BKE_sequence_invalidate_cache_raw(scene, seq_act); - BKE_sequence_invalidate_cache_raw(scene, seq_other); + SEQ_relations_invalidate_cache_raw(scene, seq_act); + SEQ_relations_invalidate_cache_raw(scene, seq_other); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -2777,8 +2704,8 @@ static const EnumPropertyItem prop_change_effect_input_types[] = { static int sequencer_change_effect_input_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); - Sequence *seq = BKE_sequencer_active_get(scene); + Editing *ed = SEQ_editing_get(scene, false); + Sequence *seq = SEQ_select_active_get(scene); Sequence **seq_1, **seq_2; @@ -2804,10 +2731,10 @@ static int sequencer_change_effect_input_exec(bContext *C, wmOperator *op) SWAP(Sequence *, *seq_1, *seq_2); - BKE_sequencer_update_changed_seq_and_deps(scene, seq, 0, 1); + SEQ_relations_update_changed_seq_and_deps(scene, seq, 0, 1); /* Invalidate cache. */ - BKE_sequencer_free_imbuf(scene, &ed->seqbase, false); + SEQ_relations_free_imbuf(scene, &ed->seqbase, false); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); return OPERATOR_FINISHED; @@ -2861,8 +2788,8 @@ EnumPropertyItem sequencer_prop_effect_types[] = { static int sequencer_change_effect_type_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); - Sequence *seq = BKE_sequencer_active_get(scene); + Editing *ed = SEQ_editing_get(scene, false); + Sequence *seq = SEQ_select_active_get(scene); const int new_type = RNA_enum_get(op->ptr, "type"); /* Free previous effect and init new effect. */ @@ -2874,23 +2801,22 @@ static int sequencer_change_effect_type_exec(bContext *C, wmOperator *op) /* Can someone explain the logic behind only allowing to increase this, * copied from 2.4x - campbell */ - if (BKE_sequence_effect_get_num_inputs(seq->type) < - BKE_sequence_effect_get_num_inputs(new_type)) { + if (SEQ_effect_get_num_inputs(seq->type) < SEQ_effect_get_num_inputs(new_type)) { BKE_report(op->reports, RPT_ERROR, "New effect needs more input strips"); return OPERATOR_CANCELLED; } - sh = BKE_sequence_get_effect(seq); + sh = SEQ_effect_handle_get(seq); sh.free(seq, true); seq->type = new_type; - sh = BKE_sequence_get_effect(seq); + sh = SEQ_effect_handle_get(seq); sh.init(seq); - BKE_sequencer_update_changed_seq_and_deps(scene, seq, 0, 1); + SEQ_relations_update_changed_seq_and_deps(scene, seq, 0, 1); /* Invalidate cache. */ - BKE_sequencer_free_imbuf(scene, &ed->seqbase, false); + SEQ_relations_free_imbuf(scene, &ed->seqbase, false); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -2928,8 +2854,8 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); - Sequence *seq = BKE_sequencer_active_get(scene); + Editing *ed = SEQ_editing_get(scene, false); + Sequence *seq = SEQ_select_active_get(scene); const bool is_relative_path = RNA_boolean_get(op->ptr, "relative_path"); const bool use_placeholders = RNA_boolean_get(op->ptr, "use_placeholders"); int minext_frameme, numdigits; @@ -2982,12 +2908,12 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op) /* Correct start/end frames so we don't move. * Important not to set seq->len = len; allow the function to handle it. */ - BKE_sequence_reload_new_file(bmain, scene, seq, true); + SEQ_add_reload_new_file(bmain, scene, seq, true); - BKE_sequence_calc(scene, seq); + SEQ_time_update_sequence(scene, seq); /* Invalidate cache. */ - BKE_sequencer_free_imbuf(scene, &ed->seqbase, false); + SEQ_relations_free_imbuf(scene, &ed->seqbase, false); } else if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) { bSound *sound = seq->sound; @@ -3021,7 +2947,7 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op) static int sequencer_change_path_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Scene *scene = CTX_data_scene(C); - Sequence *seq = BKE_sequencer_active_get(scene); + Sequence *seq = SEQ_select_active_get(scene); char filepath[FILE_MAX]; BLI_join_dirfile(filepath, sizeof(filepath), seq->strip->dir, seq->strip->stripdata->name); @@ -3105,7 +3031,7 @@ static int sequencer_export_subtitles_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); Sequence *seq, *seq_next; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); ListBase text_seq = {0}; int iter = 0; FILE *file; @@ -3144,7 +3070,7 @@ static int sequencer_export_subtitles_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - BLI_listbase_sort(&text_seq, BKE_sequencer_cmp_time_startdisp); + BLI_listbase_sort(&text_seq, SEQ_time_cmp_time_startdisp); /* Open and write file. */ file = BLI_fopen(filepath, "w"); @@ -3183,7 +3109,7 @@ static bool sequencer_strip_is_text_poll(bContext *C) { Editing *ed; Sequence *seq; - return (((ed = BKE_sequencer_editing_get(CTX_data_scene(C), false)) != NULL) && + return (((ed = SEQ_editing_get(CTX_data_scene(C), false)) != NULL) && ((seq = ed->act_seq) != NULL) && (seq->type == SEQ_TYPE_TEXT)); } @@ -3220,7 +3146,7 @@ void SEQUENCER_OT_export_subtitles(struct wmOperatorType *ot) static int sequencer_set_range_to_strips_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq; int sfra = MAXFRAME; @@ -3291,7 +3217,7 @@ void SEQUENCER_OT_set_range_to_strips(struct wmOperatorType *ot) static void set_filter_seq(Scene *scene) { Sequence *seq; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (ed == NULL) { return; @@ -3305,8 +3231,8 @@ static void set_filter_seq(Scene *scene) if (seq->flag & SELECT) { if (seq->type == SEQ_TYPE_MOVIE) { seq->flag |= SEQ_FILTERY; - BKE_sequence_reload_new_file(bmain, scene, seq, false); - BKE_sequence_calc(scene, seq); + SEQ_add_reload_new_file(bmain, scene, seq, false); + SEQ_time_update_sequence(scene, seq); } } } @@ -3315,8 +3241,8 @@ static void set_filter_seq(Scene *scene) static void UNUSED_FUNCTION(seq_remap_paths)(Scene *scene) { - Sequence *seq, *last_seq = BKE_sequencer_active_get(scene); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Sequence *seq, *last_seq = SEQ_select_active_get(scene); + Editing *ed = SEQ_editing_get(scene, false); char from[FILE_MAX], to[FILE_MAX], stripped[FILE_MAX]; if (last_seq == NULL) { @@ -3355,7 +3281,7 @@ static void UNUSED_FUNCTION(seq_remap_paths)(Scene *scene) static Sequence *sequence_find_parent(Scene *scene, Sequence *child) { - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *parent = NULL; Sequence *seq; @@ -3407,7 +3333,7 @@ Sequence *find_neighboring_sequence(Scene *scene, Sequence *test, int lr, int se { /* sel: 0==unselected, 1==selected, -1==don't care. */ Sequence *seq; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (ed == NULL) { return NULL; @@ -3441,7 +3367,7 @@ Sequence *find_neighboring_sequence(Scene *scene, Sequence *test, int lr, int se Sequence *find_nearest_seq(Scene *scene, View2D *v2d, int *hand, const int mval[2]) { Sequence *seq; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); float x, y; float pixelx; float handsize; @@ -3463,7 +3389,7 @@ Sequence *find_nearest_seq(Scene *scene, View2D *v2d, int *hand, const int mval[ /* Check for both normal strips, and strips that have been flipped horizontally. */ if (((seq->startdisp < seq->enddisp) && (seq->startdisp <= x && seq->enddisp >= x)) || ((seq->startdisp > seq->enddisp) && (seq->startdisp >= x && seq->enddisp <= x))) { - if (BKE_sequence_tx_test(seq)) { + if (SEQ_transform_sequence_can_be_translated(seq)) { /* Clamp handles to defined size in pixel space. */ handsize = 2.0f * sequence_handle_size_get_clamped(seq, pixelx); @@ -3499,3 +3425,148 @@ Sequence *find_nearest_seq(Scene *scene, View2D *v2d, int *hand, const int mval[ } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Clear Strip Transform Operator + * \{ */ + +enum { + STRIP_TRANSFORM_POSITION, + STRIP_TRANSFORM_SCALE, + STRIP_TRANSFORM_ROTATION, + STRIP_TRANSFORM_ALL, +}; + +static const EnumPropertyItem transform_reset_properties[] = { + {STRIP_TRANSFORM_POSITION, "POSITION", 0, "Position", "Reset strip transform location"}, + {STRIP_TRANSFORM_SCALE, "SCALE", 0, "Scale", "Reset strip transform scale"}, + {STRIP_TRANSFORM_ROTATION, "ROTATION", 0, "Rotation", "Reset strip transform rotation"}, + {STRIP_TRANSFORM_ALL, "ALL", 0, "All", "Reset strip transform location, scale and rotation"}, + {0, NULL, 0, NULL, NULL}, +}; + +static int sequencer_strip_transform_clear_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + const Editing *ed = SEQ_editing_get(scene, false); + Sequence *seq; + const int property = RNA_enum_get(op->ptr, "property"); + + for (seq = ed->seqbasep->first; seq; seq = seq->next) { + if (seq->flag & SELECT && seq->type != SEQ_TYPE_SOUND_RAM) { + StripTransform *transform = seq->strip->transform; + switch (property) { + case STRIP_TRANSFORM_POSITION: + transform->xofs = 0; + transform->yofs = 0; + break; + case STRIP_TRANSFORM_SCALE: + transform->scale_x = 1.0f; + transform->scale_y = 1.0f; + break; + case STRIP_TRANSFORM_ROTATION: + transform->rotation = 0.0f; + break; + case STRIP_TRANSFORM_ALL: + transform->xofs = 0; + transform->yofs = 0; + transform->scale_x = 1.0f; + transform->scale_y = 1.0f; + transform->rotation = 0.0f; + break; + } + SEQ_relations_invalidate_cache_preprocessed(scene, seq); + } + } + + WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); + return OPERATOR_FINISHED; +} + +void SEQUENCER_OT_strip_transform_clear(struct wmOperatorType *ot) +{ + /* Identifiers. */ + ot->name = "Clear Strip Transform"; + ot->idname = "SEQUENCER_OT_strip_transform_clear"; + ot->description = "Reset image transformation to default value"; + + /* Api callbacks. */ + ot->exec = sequencer_strip_transform_clear_exec; + ot->poll = sequencer_edit_poll; + + /* Flags. */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ot->prop = RNA_def_enum(ot->srna, + "property", + transform_reset_properties, + STRIP_TRANSFORM_ALL, + "Property", + "Strip transform property to be reset"); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Transform Set Fit Operator + * \{ */ + +static const EnumPropertyItem scale_fit_methods[] = { + {SEQ_SCALE_TO_FIT, "FIT", 0, "Scale to Fit", "Scale image so fits in preview"}, + {SEQ_SCALE_TO_FILL, "FILL", 0, "Scale to Fill", "Scale image so it fills preview completely"}, + {SEQ_STRETCH_TO_FILL, "STRETCH", 0, "Stretch to Fill", "Stretch image so it fills preview"}, + {0, NULL, 0, NULL, NULL}, +}; + +static int sequencer_strip_transform_fit_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + const Editing *ed = SEQ_editing_get(scene, false); + Sequence *seq; + const eSeqImageFitMethod fit_method = RNA_enum_get(op->ptr, "fit_method"); + + for (seq = ed->seqbasep->first; seq; seq = seq->next) { + if (seq->flag & SELECT && seq->type != SEQ_TYPE_SOUND_RAM) { + const int timeline_frame = CFRA; + StripElem *strip_elem = SEQ_render_give_stripelem(seq, timeline_frame); + + if (strip_elem == NULL) { + continue; + } + + SEQ_set_scale_to_fit(seq, + strip_elem->orig_width, + strip_elem->orig_height, + scene->r.xsch, + scene->r.ysch, + fit_method); + SEQ_relations_invalidate_cache_preprocessed(scene, seq); + } + } + + WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); + return OPERATOR_FINISHED; +} + +void SEQUENCER_OT_strip_transform_fit(struct wmOperatorType *ot) +{ + /* Identifiers. */ + ot->name = "Strip Transform Set Fit"; + ot->idname = "SEQUENCER_OT_strip_transform_fit"; + + /* Api callbacks. */ + ot->exec = sequencer_strip_transform_fit_exec; + ot->poll = sequencer_edit_poll; + + /* Flags. */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ot->prop = RNA_def_enum(ot->srna, + "fit_method", + scale_fit_methods, + SEQ_SCALE_TO_FIT, + "Fit Method", + "Scale fit fit_method"); +} + +/** \} */ diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h index 1ea4fb05d53..4c942a83f2b 100644 --- a/source/blender/editors/space_sequencer/sequencer_intern.h +++ b/source/blender/editors/space_sequencer/sequencer_intern.h @@ -71,7 +71,6 @@ struct ImBuf *sequencer_ibuf_get(struct Main *bmain, /* sequencer_edit.c */ struct View2D; void seq_rectf(struct Sequence *seq, struct rctf *rectf); -void boundbox_seq(struct Scene *scene, struct rctf *rect); struct Sequence *find_nearest_seq(struct Scene *scene, struct View2D *v2d, int *hand, @@ -145,6 +144,8 @@ void SEQUENCER_OT_enable_proxies(struct wmOperatorType *ot); void SEQUENCER_OT_export_subtitles(struct wmOperatorType *ot); void SEQUENCER_OT_set_range_to_strips(struct wmOperatorType *ot); +void SEQUENCER_OT_strip_transform_clear(struct wmOperatorType *ot); +void SEQUENCER_OT_strip_transform_fit(struct wmOperatorType *ot); /* sequencer_select.c */ void SEQUENCER_OT_select_all(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_sequencer/sequencer_modifier.c b/source/blender/editors/space_sequencer/sequencer_modifier.c index fb09afc6ca5..f11a879912c 100644 --- a/source/blender/editors/space_sequencer/sequencer_modifier.c +++ b/source/blender/editors/space_sequencer/sequencer_modifier.c @@ -34,6 +34,10 @@ #include "RNA_define.h" #include "RNA_enum_types.h" +#include "SEQ_iterator.h" +#include "SEQ_modifier.h" +#include "SEQ_relations.h" +#include "SEQ_select.h" #include "SEQ_sequencer.h" /* Own include. */ @@ -44,13 +48,13 @@ static bool strip_modifier_active_poll(bContext *C) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (ed) { - Sequence *seq = BKE_sequencer_active_get(scene); + Sequence *seq = SEQ_select_active_get(scene); if (seq) { - return BKE_sequence_supports_modifiers(seq); + return SEQ_sequence_supports_modifiers(seq); } } @@ -60,12 +64,12 @@ static bool strip_modifier_active_poll(bContext *C) static int strip_modifier_add_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Sequence *seq = BKE_sequencer_active_get(scene); + Sequence *seq = SEQ_select_active_get(scene); int type = RNA_enum_get(op->ptr, "type"); - BKE_sequence_modifier_new(seq, NULL, type); + SEQ_modifier_new(seq, NULL, type); - BKE_sequence_invalidate_cache_preprocessed(scene, seq); + SEQ_relations_invalidate_cache_preprocessed(scene, seq); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); return OPERATOR_FINISHED; @@ -102,21 +106,21 @@ void SEQUENCER_OT_strip_modifier_add(wmOperatorType *ot) static int strip_modifier_remove_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Sequence *seq = BKE_sequencer_active_get(scene); + Sequence *seq = SEQ_select_active_get(scene); char name[MAX_NAME]; SequenceModifierData *smd; RNA_string_get(op->ptr, "name", name); - smd = BKE_sequence_modifier_find_by_name(seq, name); + smd = SEQ_modifier_find_by_name(seq, name); if (!smd) { return OPERATOR_CANCELLED; } BLI_remlink(&seq->modifiers, smd); - BKE_sequence_modifier_free(smd); + SEQ_modifier_free(smd); - BKE_sequence_invalidate_cache_preprocessed(scene, seq); + SEQ_relations_invalidate_cache_preprocessed(scene, seq); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); return OPERATOR_FINISHED; @@ -153,7 +157,7 @@ enum { static int strip_modifier_move_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Sequence *seq = BKE_sequencer_active_get(scene); + Sequence *seq = SEQ_select_active_get(scene); char name[MAX_NAME]; int direction; SequenceModifierData *smd; @@ -161,7 +165,7 @@ static int strip_modifier_move_exec(bContext *C, wmOperator *op) RNA_string_get(op->ptr, "name", name); direction = RNA_enum_get(op->ptr, "direction"); - smd = BKE_sequence_modifier_find_by_name(seq, name); + smd = SEQ_modifier_find_by_name(seq, name); if (!smd) { return OPERATOR_CANCELLED; } @@ -179,7 +183,7 @@ static int strip_modifier_move_exec(bContext *C, wmOperator *op) } } - BKE_sequence_invalidate_cache_preprocessed(scene, seq); + SEQ_relations_invalidate_cache_preprocessed(scene, seq); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); return OPERATOR_FINISHED; @@ -225,7 +229,7 @@ static int strip_modifier_copy_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); Editing *ed = scene->ed; - Sequence *seq = BKE_sequencer_active_get(scene); + Sequence *seq = SEQ_select_active_get(scene); Sequence *seq_iter; const int type = RNA_enum_get(op->ptr, "type"); @@ -245,19 +249,19 @@ static int strip_modifier_copy_exec(bContext *C, wmOperator *op) while (smd) { smd_tmp = smd->next; BLI_remlink(&seq_iter->modifiers, smd); - BKE_sequence_modifier_free(smd); + SEQ_modifier_free(smd); smd = smd_tmp; } BLI_listbase_clear(&seq_iter->modifiers); } } - BKE_sequence_modifier_list_copy(seq_iter, seq); + SEQ_modifier_list_copy(seq_iter, seq); } } SEQ_CURRENT_END; - BKE_sequence_invalidate_cache_preprocessed(scene, seq); + SEQ_relations_invalidate_cache_preprocessed(scene, seq); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); return OPERATOR_FINISHED; diff --git a/source/blender/editors/space_sequencer/sequencer_ops.c b/source/blender/editors/space_sequencer/sequencer_ops.c index bdf6e4ece7f..7bfc8600544 100644 --- a/source/blender/editors/space_sequencer/sequencer_ops.c +++ b/source/blender/editors/space_sequencer/sequencer_ops.c @@ -81,6 +81,8 @@ void sequencer_operatortypes(void) WM_operatortype_append(SEQUENCER_OT_change_path); WM_operatortype_append(SEQUENCER_OT_set_range_to_strips); + WM_operatortype_append(SEQUENCER_OT_strip_transform_clear); + WM_operatortype_append(SEQUENCER_OT_strip_transform_fit); /* sequencer_select.c */ WM_operatortype_append(SEQUENCER_OT_select_all); diff --git a/source/blender/editors/space_sequencer/sequencer_proxy.c b/source/blender/editors/space_sequencer/sequencer_proxy.c index 2d23520814a..b04363a4f33 100644 --- a/source/blender/editors/space_sequencer/sequencer_proxy.c +++ b/source/blender/editors/space_sequencer/sequencer_proxy.c @@ -34,6 +34,9 @@ #include "BKE_main.h" #include "BKE_report.h" +#include "SEQ_iterator.h" +#include "SEQ_proxy.h" +#include "SEQ_relations.h" #include "SEQ_sequencer.h" #include "WM_api.h" @@ -90,14 +93,14 @@ static void proxy_startjob(void *pjv, short *stop, short *do_update, float *prog static void proxy_endjob(void *pjv) { ProxyJob *pj = pjv; - Editing *ed = BKE_sequencer_editing_get(pj->scene, false); + Editing *ed = SEQ_editing_get(pj->scene, false); LinkData *link; for (link = pj->queue.first; link; link = link->next) { SEQ_proxy_rebuild_finish(link->data, pj->stop); } - BKE_sequencer_free_imbuf(pj->scene, &ed->seqbase, false); + SEQ_relations_free_imbuf(pj->scene, &ed->seqbase, false); WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, pj->scene); } @@ -108,7 +111,7 @@ static void seq_proxy_build_job(const bContext *C, ReportList *reports) ProxyJob *pj; struct Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); ScrArea *area = CTX_wm_area(C); Sequence *seq; GSet *file_list; @@ -201,7 +204,7 @@ static int sequencer_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op)) Main *bmain = CTX_data_main(C); struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq; GSet *file_list; @@ -225,7 +228,7 @@ static int sequencer_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op)) SEQ_proxy_rebuild(context, &stop, &do_update, &progress); SEQ_proxy_rebuild_finish(context, 0); } - BKE_sequencer_free_imbuf(scene, &ed->seqbase, false); + SEQ_relations_free_imbuf(scene, &ed->seqbase, false); } } SEQ_CURRENT_END; @@ -266,7 +269,7 @@ static int sequencer_enable_proxies_invoke(bContext *C, static int sequencer_enable_proxies_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq; bool proxy_25 = RNA_boolean_get(op->ptr, "proxy_25"); bool proxy_50 = RNA_boolean_get(op->ptr, "proxy_50"); diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c index a6b2d7feae3..edbffa8f693 100644 --- a/source/blender/editors/space_sequencer/sequencer_select.c +++ b/source/blender/editors/space_sequencer/sequencer_select.c @@ -39,6 +39,8 @@ #include "RNA_define.h" +#include "SEQ_iterator.h" +#include "SEQ_select.h" #include "SEQ_sequencer.h" /* For menu, popup, icons, etc. */ @@ -198,13 +200,13 @@ void select_surround_from_last(Scene *scene) void ED_sequencer_select_sequence_single(Scene *scene, Sequence *seq, bool deselect_all) { - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (deselect_all) { ED_sequencer_deselect_all(scene); } - BKE_sequencer_active_set(scene, seq); + SEQ_select_active_set(scene, seq); if (ELEM(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE)) { if (seq->strip) { @@ -223,7 +225,7 @@ void ED_sequencer_select_sequence_single(Scene *scene, Sequence *seq, bool desel #if 0 static void select_neighbor_from_last(Scene *scene, int lr) { - Sequence *seq = BKE_sequencer_active_get(scene); + Sequence *seq = SEQ_select_active_get(scene); Sequence *neighbor; bool changed = false; if (seq) { @@ -264,7 +266,7 @@ static int sequencer_de_select_all_exec(bContext *C, wmOperator *op) int action = RNA_enum_get(op->ptr, "action"); Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq; if (action == SEL_TOGGLE) { @@ -331,7 +333,7 @@ void SEQUENCER_OT_select_all(struct wmOperatorType *ot) static int sequencer_select_inverse_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq; for (seq = ed->seqbasep->first; seq; seq = seq->next) { @@ -376,7 +378,7 @@ static int sequencer_select_exec(bContext *C, wmOperator *op) { View2D *v2d = UI_view2d_fromcontext(C); Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); const bool extend = RNA_boolean_get(op->ptr, "extend"); const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all"); const bool linked_handle = RNA_boolean_get(op->ptr, "linked_handle"); @@ -464,7 +466,7 @@ static int sequencer_select_exec(bContext *C, wmOperator *op) ret_value = OPERATOR_FINISHED; } - BKE_sequencer_active_set(scene, seq); + SEQ_select_active_set(scene, seq); if (ELEM(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE)) { if (seq->strip) { @@ -667,7 +669,7 @@ void SEQUENCER_OT_select(wmOperatorType *ot) /* Run recursively to select linked. */ static bool select_more_less_seq__internal(Scene *scene, bool sel, const bool linked) { - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq, *neighbor; bool changed = false; int isel; @@ -900,27 +902,84 @@ void SEQUENCER_OT_select_linked(wmOperatorType *ot) /** \name Select Handles Operator * \{ */ +enum { + SEQ_SELECT_HANDLES_SIDE_LEFT, + SEQ_SELECT_HANDLES_SIDE_RIGHT, + SEQ_SELECT_HANDLES_SIDE_BOTH, + SEQ_SELECT_HANDLES_SIDE_LEFT_NEIGHBOR, + SEQ_SELECT_HANDLES_SIDE_RIGHT_NEIGHBOR, + SEQ_SELECT_HANDLES_SIDE_BOTH_NEIGHBORS, +}; + +static const EnumPropertyItem prop_select_handles_side_types[] = { + {SEQ_SELECT_HANDLES_SIDE_LEFT, "LEFT", 0, "Left", ""}, + {SEQ_SELECT_HANDLES_SIDE_RIGHT, "RIGHT", 0, "Right", ""}, + {SEQ_SELECT_HANDLES_SIDE_BOTH, "BOTH", 0, "Both", ""}, + {SEQ_SELECT_HANDLES_SIDE_LEFT_NEIGHBOR, "LEFT_NEIGHBOR", 0, "Left Neighbor", ""}, + {SEQ_SELECT_HANDLES_SIDE_RIGHT_NEIGHBOR, "RIGHT_NEIGHBOR", 0, "Right Neighbor", ""}, + {SEQ_SELECT_HANDLES_SIDE_BOTH_NEIGHBORS, "BOTH_NEIGHBORS", 0, "Both Neighbors", ""}, + {0, NULL, 0, NULL, NULL}, +}; + static int sequencer_select_handles_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq; int sel_side = RNA_enum_get(op->ptr, "side"); for (seq = ed->seqbasep->first; seq; seq = seq->next) { if (seq->flag & SELECT) { + Sequence *l_neighbor = find_neighboring_sequence(scene, seq, SEQ_SIDE_LEFT, -1); + Sequence *r_neighbor = find_neighboring_sequence(scene, seq, SEQ_SIDE_RIGHT, -1); + switch (sel_side) { - case SEQ_SIDE_LEFT: + case SEQ_SELECT_HANDLES_SIDE_LEFT: seq->flag &= ~SEQ_RIGHTSEL; seq->flag |= SEQ_LEFTSEL; break; - case SEQ_SIDE_RIGHT: + case SEQ_SELECT_HANDLES_SIDE_RIGHT: seq->flag &= ~SEQ_LEFTSEL; seq->flag |= SEQ_RIGHTSEL; break; - case SEQ_SIDE_BOTH: + case SEQ_SELECT_HANDLES_SIDE_BOTH: seq->flag |= SEQ_LEFTSEL | SEQ_RIGHTSEL; break; + case SEQ_SELECT_HANDLES_SIDE_LEFT_NEIGHBOR: + if (l_neighbor) { + if (!(l_neighbor->flag & SELECT)) { + l_neighbor->flag |= SEQ_RIGHTSEL; + } + } + break; + case SEQ_SELECT_HANDLES_SIDE_RIGHT_NEIGHBOR: + if (r_neighbor) { + if (!(r_neighbor->flag & SELECT)) { + r_neighbor->flag |= SEQ_LEFTSEL; + } + } + break; + case SEQ_SELECT_HANDLES_SIDE_BOTH_NEIGHBORS: + if (l_neighbor) { + if (!(l_neighbor->flag & SELECT)) { + l_neighbor->flag |= SEQ_RIGHTSEL; + } + } + if (r_neighbor) { + if (!(r_neighbor->flag & SELECT)) { + r_neighbor->flag |= SEQ_LEFTSEL; + } + break; + } + } + } + } + /* Select strips */ + for (seq = ed->seqbasep->first; seq; seq = seq->next) { + if ((seq->flag & SEQ_LEFTSEL) || (seq->flag & SEQ_RIGHTSEL)) { + if (!(seq->flag & SELECT)) { + seq->flag |= SELECT; + recurs_sel_seq(seq); } } } @@ -949,8 +1008,8 @@ void SEQUENCER_OT_select_handles(wmOperatorType *ot) /* Properties. */ RNA_def_enum(ot->srna, "side", - prop_side_types, - SEQ_SIDE_BOTH, + prop_select_handles_side_types, + SEQ_SELECT_HANDLES_SIDE_BOTH, "Side", "The side of the handle that is selected"); } @@ -964,7 +1023,7 @@ void SEQUENCER_OT_select_handles(wmOperatorType *ot) static int sequencer_select_side_of_frame_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); const bool extend = RNA_boolean_get(op->ptr, "extend"); const int side = RNA_enum_get(op->ptr, "side"); Sequence *seq; @@ -1038,7 +1097,7 @@ void SEQUENCER_OT_select_side_of_frame(wmOperatorType *ot) static int sequencer_select_side_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); const int sel_side = RNA_enum_get(op->ptr, "side"); const int frame_init = sel_side == SEQ_SIDE_LEFT ? INT_MIN : INT_MAX; @@ -1109,7 +1168,7 @@ static int sequencer_box_select_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); View2D *v2d = UI_view2d_fromcontext(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (ed == NULL) { return OPERATOR_CANCELLED; @@ -1454,8 +1513,7 @@ static bool select_grouped_effect_link(Editing *ed, Sequence *actseq, const int actseq->tmp = POINTER_FROM_INT(true); - for (BKE_sequence_iterator_begin(ed, &iter, true); iter.valid; - BKE_sequence_iterator_next(&iter)) { + for (SEQ_iterator_begin(ed, &iter, true); iter.valid; SEQ_iterator_next(&iter)) { seq = iter.seq; /* Ignore all seqs already selected. */ @@ -1486,8 +1544,8 @@ static bool select_grouped_effect_link(Editing *ed, Sequence *actseq, const int changed = true; /* Unfortunately, we must restart checks from the beginning. */ - BKE_sequence_iterator_end(&iter); - BKE_sequence_iterator_begin(ed, &iter, true); + SEQ_iterator_end(&iter); + SEQ_iterator_begin(ed, &iter, true); } /* Video strips below active one, or any strip for audio (order doesn't matter here). */ @@ -1496,7 +1554,7 @@ static bool select_grouped_effect_link(Editing *ed, Sequence *actseq, const int changed = true; } } - BKE_sequence_iterator_end(&iter); + SEQ_iterator_end(&iter); return changed; } @@ -1508,8 +1566,8 @@ static bool select_grouped_effect_link(Editing *ed, Sequence *actseq, const int static int sequencer_select_grouped_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); - Sequence *seq, *actseq = BKE_sequencer_active_get(scene); + Editing *ed = SEQ_editing_get(scene, false); + Sequence *seq, *actseq = SEQ_select_active_get(scene); if (actseq == NULL) { BKE_report(op->reports, RPT_ERROR, "No active sequence!"); diff --git a/source/blender/editors/space_sequencer/sequencer_view.c b/source/blender/editors/space_sequencer/sequencer_view.c index 75d92d5f00d..8805d5af227 100644 --- a/source/blender/editors/space_sequencer/sequencer_view.c +++ b/source/blender/editors/space_sequencer/sequencer_view.c @@ -38,7 +38,9 @@ #include "RNA_define.h" +#include "SEQ_select.h" #include "SEQ_sequencer.h" +#include "SEQ_time.h" /* For menu, popup, icons, etc. */ #include "ED_anim_api.h" @@ -87,8 +89,10 @@ static int sequencer_view_all_exec(bContext *C, wmOperator *op) rctf box; const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); + Scene *scene = CTX_data_scene(C); + const Editing *ed = SEQ_editing_get(scene, false); - boundbox_seq(CTX_data_scene(C), &box); + SEQ_timeline_boundbox(scene, SEQ_active_seqbase_get(ed), &box); UI_view2d_smooth_view(C, region, &box, smooth_viewtx); return OPERATOR_FINISHED; } @@ -270,8 +274,8 @@ static int sequencer_view_selected_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); View2D *v2d = UI_view2d_fromcontext(C); ARegion *region = CTX_wm_region(C); - Editing *ed = BKE_sequencer_editing_get(scene, false); - Sequence *last_seq = BKE_sequencer_active_get(scene); + Editing *ed = SEQ_editing_get(scene, false); + Sequence *last_seq = SEQ_select_active_get(scene); Sequence *seq; rctf cur_new = v2d->cur; diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index 45c7bac54f8..b11e2a32b87 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -52,6 +52,7 @@ #include "RNA_access.h" #include "SEQ_sequencer.h" +#include "SEQ_utils.h" #include "UI_interface.h" #include "UI_resources.h" @@ -99,7 +100,8 @@ static SpaceLink *sequencer_create(const ScrArea *UNUSED(area), const Scene *sce sseq->view = SEQ_VIEW_SEQUENCE; sseq->mainb = SEQ_DRAW_IMG_IMBUF; sseq->flag = SEQ_SHOW_GPENCIL | SEQ_USE_ALPHA | SEQ_SHOW_MARKERS | SEQ_SHOW_FCURVES | - SEQ_ZOOM_TO_FIT; + SEQ_ZOOM_TO_FIT | SEQ_SHOW_STRIP_OVERLAY | SEQ_SHOW_STRIP_NAME | + SEQ_SHOW_STRIP_SOURCE | SEQ_SHOW_STRIP_DURATION; /* Tool header. */ region = MEM_callocN(sizeof(ARegion), "tool header for sequencer"); @@ -470,7 +472,7 @@ static int /*eContextResult*/ sequencer_context(const bContext *C, return CTX_RESULT_OK; } if (CTX_data_equals(member, "edit_mask")) { - Mask *mask = BKE_sequencer_mask_get(scene); + Mask *mask = SEQ_active_mask_get(scene); if (mask) { CTX_data_id_pointer_set(result, &mask->id); } @@ -706,7 +708,8 @@ static void sequencer_preview_region_draw(const bContext *C, ARegion *region) SpaceSeq *sseq = area->spacedata.first; Scene *scene = CTX_data_scene(C); wmWindowManager *wm = CTX_wm_manager(C); - const bool draw_overlay = (scene->ed && (scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW)); + const bool draw_overlay = (scene->ed && (scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW) && + (sseq->flag & SEQ_SHOW_STRIP_OVERLAY)); /* XXX temp fix for wrong setting in sseq->mainb */ if (sseq->mainb == SEQ_DRAW_SEQUENCE) { diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c index bb71a9b11be..0f5ac5abe1d 100644 --- a/source/blender/editors/space_text/space_text.c +++ b/source/blender/editors/space_text/space_text.c @@ -357,7 +357,7 @@ static bool text_drop_paste_poll(bContext *UNUSED(C), static void text_drop_paste(wmDrag *drag, wmDropBox *drop) { char *text; - ID *id = WM_drag_ID(drag, 0); + ID *id = WM_drag_get_local_ID(drag, 0); /* copy drag path to properties */ text = RNA_path_full_ID_py(G_MAIN, id); diff --git a/source/blender/editors/space_text/text_header.c b/source/blender/editors/space_text/text_header.c index c583634f440..84b7a6f6831 100644 --- a/source/blender/editors/space_text/text_header.c +++ b/source/blender/editors/space_text/text_header.c @@ -108,101 +108,3 @@ void TEXT_OT_start_find(wmOperatorType *ot) ot->exec = text_text_search_exec; ot->poll = text_properties_poll; } - -/******************** XXX popup menus *******************/ - -#if 0 -{ - /* RMB */ - - uiPopupMenu *pup; - - if (text) { - pup = UI_popup_menu_begin(C, IFACE_("Text"), ICON_NONE); - if (txt_has_sel(text)) { - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_cut"); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_copy"); - } - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_paste"); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_new"); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_open"); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_save"); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_save_as"); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_run_script"); - UI_popup_menu_end(C, pup); - } - else { - pup = UI_popup_menu_begin(C, IFACE_("File"), ICON_NONE); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_new"); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_open"); - UI_popup_menu_end(C, pup); - } -} - -{ - /* Alt+Shift+E */ - - uiPopupMenu *pup; - - pup = UI_popup_menu_begin(C, IFACE_("Edit"), ICON_NONE); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_cut"); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_copy"); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_paste"); - UI_popup_menu_end(C, pup); -} - -{ - /* Alt+Shift+F */ - - uiPopupMenu *pup; - - if (text) { - pup = UI_popup_menu_begin(C, IFACE_("Text"), ICON_NONE); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_new"); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_open"); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_save"); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_save_as"); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_run_script"); - UI_popup_menu_end(C, pup); - } - else { - pup = UI_popup_menu_begin(C, IFACE_("File"), ICON_NONE); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_new"); - uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_open"); - UI_popup_menu_end(C, pup); - } -} - -{ - /* Alt+Shift+V */ - - uiPopupMenu *pup; - - pup = UI_popup_menu_begin(C, IFACE_("Text"), ICON_NONE); - uiItemEnumO(layout, - "TEXT_OT_move", - CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Top of File"), - 0, - "type", - FILE_TOP); - uiItemEnumO(layout, - "TEXT_OT_move", - CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Bottom of File"), - 0, - "type", - FILE_BOTTOM); - uiItemEnumO(layout, - "TEXT_OT_move", - CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Page Up"), - 0, - "type", - PREV_PAGE); - uiItemEnumO(layout, - "TEXT_OT_move", - CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Page Down"), - 0, - "type", - NEXT_PAGE); - UI_popup_menu_end(C, pup); -} -#endif diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index f8b7c62686f..932bacfb8a0 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -2588,7 +2588,7 @@ static int text_scroll_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - txt_screen_skip(st, region, lines * U.wheellinescroll); + txt_screen_skip(st, region, lines * 3); ED_area_tag_redraw(CTX_wm_area(C)); diff --git a/source/blender/editors/space_userpref/userpref_ops.c b/source/blender/editors/space_userpref/userpref_ops.c index d823530fd89..f05d6df9944 100644 --- a/source/blender/editors/space_userpref/userpref_ops.c +++ b/source/blender/editors/space_userpref/userpref_ops.c @@ -30,6 +30,7 @@ #include "BKE_context.h" #include "BKE_global.h" #include "BKE_main.h" +#include "BKE_preferences.h" #include "BKE_report.h" #include "RNA_access.h" @@ -92,7 +93,7 @@ static int preferences_autoexec_add_exec(bContext *UNUSED(C), wmOperator *UNUSED static void PREFERENCES_OT_autoexec_path_add(wmOperatorType *ot) { - ot->name = "Add Autoexec Path"; + ot->name = "Add Auto-Execution Path"; ot->idname = "PREFERENCES_OT_autoexec_path_add"; ot->description = "Add path to exclude from auto-execution"; @@ -120,7 +121,7 @@ static int preferences_autoexec_remove_exec(bContext *UNUSED(C), wmOperator *op) static void PREFERENCES_OT_autoexec_path_remove(wmOperatorType *ot) { - ot->name = "Remove Autoexec Path"; + ot->name = "Remove Auto-Execution Path"; ot->idname = "PREFERENCES_OT_autoexec_path_remove"; ot->description = "Remove path to exclude from auto-execution"; @@ -133,9 +134,71 @@ static void PREFERENCES_OT_autoexec_path_remove(wmOperatorType *ot) /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Add Asset Library Operator + * \{ */ + +static int preferences_asset_library_add_exec(bContext *UNUSED(C), wmOperator *UNUSED(op)) +{ + BKE_preferences_asset_library_add(&U, NULL, NULL); + U.runtime.is_dirty = true; + return OPERATOR_FINISHED; +} + +static void PREFERENCES_OT_asset_library_add(wmOperatorType *ot) +{ + ot->name = "Add Asset Library"; + ot->idname = "PREFERENCES_OT_asset_library_add"; + ot->description = + "Add a path to a .blend file to be used by the Asset Browser as source of assets"; + + ot->exec = preferences_asset_library_add_exec; + + ot->flag = OPTYPE_INTERNAL; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Remove Asset Library Operator + * \{ */ + +static int preferences_asset_library_remove_exec(bContext *UNUSED(C), wmOperator *op) +{ + const int index = RNA_int_get(op->ptr, "index"); + bUserAssetLibrary *library = BLI_findlink(&U.asset_libraries, index); + if (library) { + BKE_preferences_asset_library_remove(&U, library); + U.runtime.is_dirty = true; + /* Trigger refresh for the Asset Browser. */ + WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, NULL); + } + return OPERATOR_FINISHED; +} + +static void PREFERENCES_OT_asset_library_remove(wmOperatorType *ot) +{ + ot->name = "Remove Asset Library"; + ot->idname = "PREFERENCES_OT_asset_library_remove"; + ot->description = + "Remove a path to a .blend file, so the Asset Browser will not attempt to show it anymore"; + + ot->exec = preferences_asset_library_remove_exec; + + ot->flag = OPTYPE_INTERNAL; + + RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000); +} + +/** \} */ + void ED_operatortypes_userpref(void) { WM_operatortype_append(PREFERENCES_OT_reset_default_theme); + WM_operatortype_append(PREFERENCES_OT_autoexec_path_add); WM_operatortype_append(PREFERENCES_OT_autoexec_path_remove); + + WM_operatortype_append(PREFERENCES_OT_asset_library_add); + WM_operatortype_append(PREFERENCES_OT_asset_library_remove); } diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt index 0371b4e271f..9242fc15021 100644 --- a/source/blender/editors/space_view3d/CMakeLists.txt +++ b/source/blender/editors/space_view3d/CMakeLists.txt @@ -22,13 +22,13 @@ set(INC ../../blenlib ../../blentranslation ../../bmesh + ../../depsgraph ../../draw ../../gpu ../../imbuf ../../makesdna ../../makesrna ../../render - ../../depsgraph ../../windowmanager ../../../../intern/glew-mx ../../../../intern/guardedalloc diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 9f31e7a411d..3761f4ad7c6 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -461,6 +461,12 @@ static void view3d_main_region_exit(wmWindowManager *wm, ARegion *region) ED_view3d_stop_render_preview(wm, region); } +static bool view3d_drop_in_main_region_poll(bContext *C, const wmEvent *event) +{ + ScrArea *area = CTX_wm_area(C); + return ED_region_overlap_isect_any_xy(area, &event->x) == false; +} + static ID *view3d_drop_id_in_main_region_poll_id(bContext *C, wmDrag *drag, const wmEvent *event, @@ -470,7 +476,7 @@ static ID *view3d_drop_id_in_main_region_poll_id(bContext *C, if (ED_region_overlap_isect_any_xy(area, &event->x)) { return NULL; } - return WM_drag_ID(drag, id_type); + return view3d_drop_in_main_region_poll(C, event) ? WM_drag_get_local_ID(drag, id_type) : NULL; } static bool view3d_drop_id_in_main_region_poll(bContext *C, @@ -478,7 +484,11 @@ static bool view3d_drop_id_in_main_region_poll(bContext *C, const wmEvent *event, ID_Type id_type) { - return (view3d_drop_id_in_main_region_poll_id(C, drag, event, id_type) != NULL); + if (!view3d_drop_in_main_region_poll(C, event)) { + return false; + } + + return WM_drag_get_local_ID(drag, id_type) || WM_drag_get_asset_data(drag, id_type); } static bool view3d_ob_drop_poll(bContext *C, @@ -533,7 +543,7 @@ static bool view3d_ima_drop_poll(bContext *C, return (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_MOVIE)); } - return WM_drag_ID(drag, ID_IM) != NULL; + return WM_drag_get_local_ID(drag, ID_IM) || WM_drag_get_asset_data(drag, ID_IM); } static bool view3d_ima_bg_is_camera_view(bContext *C) @@ -596,14 +606,14 @@ static bool view3d_volume_drop_poll(bContext *UNUSED(C), static void view3d_ob_drop_copy(wmDrag *drag, wmDropBox *drop) { - ID *id = WM_drag_ID(drag, ID_OB); + ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, ID_OB); RNA_string_set(drop->ptr, "name", id->name + 2); } static void view3d_collection_drop_copy(wmDrag *drag, wmDropBox *drop) { - ID *id = WM_drag_ID(drag, ID_GR); + ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, ID_GR); drop->opcontext = WM_OP_EXEC_DEFAULT; RNA_string_set(drop->ptr, "name", id->name + 2); @@ -611,14 +621,14 @@ static void view3d_collection_drop_copy(wmDrag *drag, wmDropBox *drop) static void view3d_id_drop_copy(wmDrag *drag, wmDropBox *drop) { - ID *id = WM_drag_ID(drag, 0); + ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0); RNA_string_set(drop->ptr, "name", id->name + 2); } static void view3d_id_drop_copy_with_type(wmDrag *drag, wmDropBox *drop) { - ID *id = WM_drag_ID(drag, 0); + ID *id = WM_drag_get_local_ID(drag, 0); RNA_string_set(drop->ptr, "name", id->name + 2); RNA_enum_set(drop->ptr, "type", GS(id->name)); @@ -626,7 +636,7 @@ static void view3d_id_drop_copy_with_type(wmDrag *drag, wmDropBox *drop) static void view3d_id_path_drop_copy(wmDrag *drag, wmDropBox *drop) { - ID *id = WM_drag_ID(drag, 0); + ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0); if (id) { RNA_string_set(drop->ptr, "name", id->name + 2); diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 9429da342a6..ebfa4f6d9af 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -4708,7 +4708,7 @@ static int viewpersportho_exec(bContext *C, wmOperator *UNUSED(op)) void VIEW3D_OT_view_persportho(wmOperatorType *ot) { /* identifiers */ - ot->name = "View Persp/Ortho"; + ot->name = "View Perspective/Orthographic"; ot->description = "Switch the current view from perspective/orthographic projection"; ot->idname = "VIEW3D_OT_view_persportho"; diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c index fdba74ed3a6..9b0ce27b1e3 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c @@ -315,8 +315,6 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph, const float eps_bias = 0.0002f; float dist_px = MVAL_MAX_PX_DIST * U.pixelsize; /* snap dist */ - WM_gizmo_set_flag(snap_gizmo, WM_GIZMO_HIDDEN, true); - if (ruler_item) { RulerInteraction *inter = ruler_item->gz.interaction_data; float *co = ruler_item->co[inter->co_index]; @@ -388,12 +386,8 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph, snap_gizmo->ptr, ruler_info->snap_data.prop_prevpoint, prev_point); } - short snap_elem = ED_gizmotypes_snap_3d_update( + ED_gizmotypes_snap_3d_update( snap_gizmo, depsgraph, ruler_info->region, v3d, ruler_info->wm, mval_fl, co, NULL); - - if (snap_elem) { - WM_gizmo_set_flag(snap_gizmo, WM_GIZMO_HIDDEN, false); - } } return true; } @@ -1074,7 +1068,6 @@ static void gizmo_ruler_exit(bContext *C, wmGizmo *gz, const bool cancel) if (!cancel) { if (ruler_info->state == RULER_STATE_DRAG) { - WM_gizmo_set_flag(ruler_info->snap_data.gizmo, WM_GIZMO_HIDDEN, false); RNA_property_unset(ruler_info->snap_data.gizmo->ptr, ruler_info->snap_data.prop_prevpoint); ruler_state_set(ruler_info, RULER_STATE_NORMAL); } diff --git a/source/blender/editors/space_view3d/view3d_placement.c b/source/blender/editors/space_view3d/view3d_placement.c index 6d10aa5f957..bd71a768c0f 100644 --- a/source/blender/editors/space_view3d/view3d_placement.c +++ b/source/blender/editors/space_view3d/view3d_placement.c @@ -72,7 +72,7 @@ static void preview_plane_cursor_visible_set(wmGizmoGroup *gzgroup, bool do_draw * In this case we can't usefully project the mouse cursor onto the plane, * so use a fall-back plane instead. */ -const float eps_view_align = 1e-2f; +static const float eps_view_align = 1e-2f; /* -------------------------------------------------------------------- */ /** \name Local Types @@ -1357,7 +1357,6 @@ static int view3d_interactive_add_modal(bContext *C, wmOperator *op, const wmEve const float mval_fl[2] = {UNPACK2(event->mval)}; /* Calculate the snap location on mouse-move or when toggling snap. */ - bool is_snap_found_prev = ipd->is_snap_found; ipd->is_snap_found = false; if (ipd->use_snap) { if (ipd->snap_gizmo != NULL) { @@ -1366,7 +1365,7 @@ static int view3d_interactive_add_modal(bContext *C, wmOperator *op, const wmEve CTX_data_ensure_evaluated_depsgraph(C), ipd->region, ipd->v3d, - NULL, + G_MAIN->wm.first, mval_fl, ipd->snap_co, NULL)) { @@ -1376,12 +1375,6 @@ static int view3d_interactive_add_modal(bContext *C, wmOperator *op, const wmEve } } - /* Workaround because test_select doesn't run at the same time as the modal operator. */ - if (is_snap_found_prev != ipd->is_snap_found) { - wmGizmoMap *gzmap = ipd->region->gizmo_map; - WM_gizmo_highlight_set(gzmap, ipd->is_snap_found ? ipd->snap_gizmo : NULL); - } - if (ipd->step_index == STEP_BASE) { if (ipd->is_snap_found) { closest_to_plane_normalized_v3( diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 5b400bbf60a..96bd25f85e7 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -2457,13 +2457,16 @@ static int view3d_select_exec(bContext *C, wmOperator *op) else if (obact && BKE_paint_select_face_test(obact)) { retval = paintface_mouse_select(C, obact, location, extend, deselect, toggle); if (!retval && deselect_all) { - retval = paintface_deselect_all_visible(C, CTX_data_active_object(C), SEL_DESELECT, false); + retval = paintface_deselect_all_visible(C, CTX_data_active_object(C), SEL_DESELECT, true); } } else if (BKE_paint_select_vert_test(obact)) { retval = ed_wpaint_vertex_select_pick(C, location, extend, deselect, toggle, obact); if (!retval && deselect_all) { retval = paintvert_deselect_all_visible(obact, SEL_DESELECT, false); + if (retval) { + paintvert_tag_select_update(C, obact); + } } } else { diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c index 1be9bd27c7a..2b7b8255068 100644 --- a/source/blender/editors/space_view3d/view3d_utils.c +++ b/source/blender/editors/space_view3d/view3d_utils.c @@ -1620,6 +1620,41 @@ void ED_view3d_to_object(const Depsgraph *depsgraph, BKE_object_apply_mat4_ex(ob, mat, ob_eval->parent, ob_eval->parentinv, true); } +bool ED_view3d_camera_to_view_selected(struct Main *bmain, + Depsgraph *depsgraph, + const Scene *scene, + Object *camera_ob) +{ + Object *camera_ob_eval = DEG_get_evaluated_object(depsgraph, camera_ob); + float co[3]; /* the new location to apply */ + float scale; /* only for ortho cameras */ + + if (BKE_camera_view_frame_fit_to_scene(depsgraph, scene, camera_ob_eval, co, &scale)) { + ObjectTfmProtectedChannels obtfm; + float obmat_new[4][4]; + + if ((camera_ob_eval->type == OB_CAMERA) && + (((Camera *)camera_ob_eval->data)->type == CAM_ORTHO)) { + ((Camera *)camera_ob->data)->ortho_scale = scale; + } + + copy_m4_m4(obmat_new, camera_ob_eval->obmat); + copy_v3_v3(obmat_new[3], co); + + /* only touch location */ + BKE_object_tfm_protected_backup(camera_ob, &obtfm); + BKE_object_apply_mat4(camera_ob, obmat_new, true, true); + BKE_object_tfm_protected_restore(camera_ob, &obtfm, OB_LOCK_SCALE | OB_LOCK_ROT4D); + + /* notifiers */ + DEG_id_tag_update_ex(bmain, &camera_ob->id, ID_RECALC_TRANSFORM); + + return true; + } + + return false; +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index a24f59019f0..9d947384bf0 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -535,40 +535,18 @@ void VIEW3D_OT_camera_to_view(wmOperatorType *ot) * meant to take into account vertex/bone selection for eg. */ static int view3d_camera_to_view_selected_exec(bContext *C, wmOperator *op) { + Main *bmain = CTX_data_main(C); Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); /* can be NULL */ Object *camera_ob = v3d ? v3d->camera : scene->camera; - Object *camera_ob_eval = DEG_get_evaluated_object(depsgraph, camera_ob); - - float r_co[3]; /* the new location to apply */ - float r_scale; /* only for ortho cameras */ - if (camera_ob_eval == NULL) { + if (camera_ob == NULL) { BKE_report(op->reports, RPT_ERROR, "No active camera"); return OPERATOR_CANCELLED; } - /* this function does all the important stuff */ - if (BKE_camera_view_frame_fit_to_scene(depsgraph, scene, camera_ob_eval, r_co, &r_scale)) { - ObjectTfmProtectedChannels obtfm; - float obmat_new[4][4]; - - if ((camera_ob_eval->type == OB_CAMERA) && - (((Camera *)camera_ob_eval->data)->type == CAM_ORTHO)) { - ((Camera *)camera_ob->data)->ortho_scale = r_scale; - } - - copy_m4_m4(obmat_new, camera_ob_eval->obmat); - copy_v3_v3(obmat_new[3], r_co); - - /* only touch location */ - BKE_object_tfm_protected_backup(camera_ob, &obtfm); - BKE_object_apply_mat4(camera_ob, obmat_new, true, true); - BKE_object_tfm_protected_restore(camera_ob, &obtfm, OB_LOCK_SCALE | OB_LOCK_ROT4D); - - /* notifiers */ - DEG_id_tag_update(&camera_ob->id, ID_RECALC_TRANSFORM); + if (ED_view3d_camera_to_view_selected(bmain, depsgraph, scene, camera_ob)) { WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, camera_ob); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt index 73d6a376da6..a2eb68a1b71 100644 --- a/source/blender/editors/transform/CMakeLists.txt +++ b/source/blender/editors/transform/CMakeLists.txt @@ -22,12 +22,12 @@ set(INC ../../blenlib ../../blentranslation ../../bmesh + ../../depsgraph ../../gpu ../../ikplugin ../../makesdna ../../makesrna ../../render - ../../depsgraph ../../sequencer ../../windowmanager ../../../../intern/glew-mx diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 5969de5b5da..2b56b30be90 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -637,6 +637,14 @@ static bool transform_modal_item_poll(const wmOperator *op, int value) } break; } + case TFM_MODAL_TRANSLATE: + case TFM_MODAL_ROTATE: + case TFM_MODAL_RESIZE: { + if (!transform_mode_is_changeable(t->mode)) { + return false; + } + break; + } } return true; } @@ -876,11 +884,6 @@ int transformEvent(TransInfo *t, const wmEvent *event) handled = true; } } - else if (t->mode == TFM_SEQ_SLIDE) { - t->flag ^= T_ALT_TRANSFORM; - t->redraw |= TREDRAW_HARD; - handled = true; - } else if (transform_mode_is_changeable(t->mode)) { restoreTransObjects(t); resetTransModal(t); @@ -922,11 +925,6 @@ int transformEvent(TransInfo *t, const wmEvent *event) handled = true; } } - else if (t->mode == TFM_SHRINKFATTEN) { - t->flag ^= T_ALT_TRANSFORM; - t->redraw |= TREDRAW_HARD; - handled = true; - } else if (transform_mode_is_changeable(t->mode)) { /* Scale isn't normally very useful after extrude along normals, see T39756 */ if ((t->con.mode & CON_APPLY) && (t->orient[t->orient_curr].type == V3D_ORIENT_NORMAL)) { diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 227330e8524..91bf2bf8aac 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -52,12 +52,12 @@ struct SnapObjectContext; struct TransDataContainer; struct TransInfo; struct TransSnap; -struct TransformOrientation; struct ViewLayer; struct bContext; struct wmEvent; struct wmKeyConfig; struct wmKeyMap; +struct wmOperator; struct wmTimer; /** #TransInfo.redraw */ diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c index c23ee5b771c..c81c954bd0a 100644 --- a/source/blender/editors/transform/transform_convert.c +++ b/source/blender/editors/transform/transform_convert.c @@ -1438,7 +1438,7 @@ void animrecord_check_state(TransInfo *t, struct Object *ob) /* only push down if action is more than 1-2 frames long */ calc_action_range(adt->action, &astart, &aend, 1); if (aend > astart + 2.0f) { - NlaStrip *strip = BKE_nlastack_add_strip(adt, adt->action); + NlaStrip *strip = BKE_nlastack_add_strip(adt, adt->action, ID_IS_OVERRIDE_LIBRARY(id)); /* clear reference to action now that we've pushed it onto the stack */ id_us_min(&adt->action->id); diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h index b753572ea7b..59fcd016020 100644 --- a/source/blender/editors/transform/transform_convert.h +++ b/source/blender/editors/transform/transform_convert.h @@ -29,12 +29,9 @@ struct FCurve; struct ListBase; struct Object; struct TransData; -struct TransDataContainer; struct TransDataCurveHandleFlags; struct TransInfo; struct bContext; -struct bKinematicConstraint; -struct bPoseChannel; /* transform_convert.c */ void transform_autoik_update(TransInfo *t, short mode); diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c index a7301161570..e9b2273b343 100644 --- a/source/blender/editors/transform/transform_convert_armature.c +++ b/source/blender/editors/transform/transform_convert_armature.c @@ -164,21 +164,21 @@ static void autokeyframe_pose( /* only if bone name matches too... * NOTE: this will do constraints too, but those are ok to do here too? */ - if (pchanName && STREQ(pchanName, pchan->name)) { - insert_keyframe(bmain, - reports, - id, - act, - ((fcu->grp) ? (fcu->grp->name) : (NULL)), - fcu->rna_path, - fcu->array_index, - &anim_eval_context, - ts->keyframe_type, - &nla_cache, - flag); - } - if (pchanName) { + if (STREQ(pchanName, pchan->name)) { + insert_keyframe(bmain, + reports, + id, + act, + ((fcu->grp) ? (fcu->grp->name) : (NULL)), + fcu->rna_path, + fcu->array_index, + &anim_eval_context, + ts->keyframe_type, + &nla_cache, + flag); + } + MEM_freeN(pchanName); } } diff --git a/source/blender/editors/transform/transform_convert_nla.c b/source/blender/editors/transform/transform_convert_nla.c index 8f18f6a8c96..fa60a88a45b 100644 --- a/source/blender/editors/transform/transform_convert_nla.c +++ b/source/blender/editors/transform/transform_convert_nla.c @@ -462,6 +462,12 @@ void recalcData_nla(TransInfo *t) * - we need to calculate both, * as only one may have been altered by transform if only 1 handle moved. */ + /* In LibOverride case, we cannot move strips across tracks that come from the linked data. */ + const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(tdn->id); + if (BKE_nlatrack_is_nonlocal_in_liboverride(tdn->id, tdn->nlt)) { + continue; + } + delta_y1 = ((int)tdn->h1[1] / NLACHANNEL_STEP(snla) - tdn->trackIndex); delta_y2 = ((int)tdn->h2[1] / NLACHANNEL_STEP(snla) - tdn->trackIndex); @@ -477,10 +483,11 @@ void recalcData_nla(TransInfo *t) if (delta > 0) { for (track = tdn->nlt->next, n = 0; (track) && (n < delta); track = track->next, n++) { /* check if space in this track for the strip */ - if (BKE_nlatrack_has_space(track, strip->start, strip->end)) { + if (BKE_nlatrack_has_space(track, strip->start, strip->end) && + !BKE_nlatrack_is_nonlocal_in_liboverride(tdn->id, tdn->nlt)) { /* move strip to this track */ BLI_remlink(&tdn->nlt->strips, strip); - BKE_nlatrack_add_strip(track, strip); + BKE_nlatrack_add_strip(track, strip, is_liboverride); tdn->nlt = track; tdn->trackIndex++; @@ -496,10 +503,11 @@ void recalcData_nla(TransInfo *t) for (track = tdn->nlt->prev, n = 0; (track) && (n < delta); track = track->prev, n++) { /* check if space in this track for the strip */ - if (BKE_nlatrack_has_space(track, strip->start, strip->end)) { + if (BKE_nlatrack_has_space(track, strip->start, strip->end) && + !BKE_nlatrack_is_nonlocal_in_liboverride(tdn->id, tdn->nlt)) { /* move strip to this track */ BLI_remlink(&tdn->nlt->strips, strip); - BKE_nlatrack_add_strip(track, strip); + BKE_nlatrack_add_strip(track, strip, is_liboverride); tdn->nlt = track; tdn->trackIndex--; diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c index 3f86ef3e81b..ebb0b6823a3 100644 --- a/source/blender/editors/transform/transform_convert_sequencer.c +++ b/source/blender/editors/transform/transform_convert_sequencer.c @@ -32,7 +32,11 @@ #include "ED_markers.h" +#include "SEQ_relations.h" #include "SEQ_sequencer.h" +#include "SEQ_time.h" +#include "SEQ_transform.h" +#include "SEQ_utils.h" #include "UI_view2d.h" @@ -84,8 +88,8 @@ static void SeqTransInfo(TransInfo *t, Sequence *seq, int *r_recursive, int *r_c Scene *scene = t->scene; int cfra = CFRA; - int left = BKE_sequence_tx_get_final_left(seq, true); - int right = BKE_sequence_tx_get_final_right(seq, true); + int left = SEQ_transform_get_left_handle_frame(seq, true); + int right = SEQ_transform_get_right_handle_frame(seq, true); if (seq->depth == 0 && ((seq->flag & SELECT) == 0 || (seq->flag & SEQ_LOCK))) { *r_recursive = false; @@ -186,7 +190,7 @@ static void SeqTransInfo(TransInfo *t, Sequence *seq, int *r_recursive, int *r_c /* Meta's can only directly be moved between channels since they * don't have their start and length set directly (children affect that) * since this Meta is nested we don't need any of its data in fact. - * BKE_sequence_calc() will update its settings when run on the top-level meta. */ + * SEQ_time_update_sequence() will update its settings when run on the top-level meta. */ *r_flag = 0; *r_count = 0; *r_recursive = true; @@ -235,16 +239,16 @@ static TransData *SeqToTransData( /* Use seq_tx_get_final_left() and an offset here * so transform has the left hand location of the strip. * tdsq->start_offset is used when flushing the tx data back */ - start_left = BKE_sequence_tx_get_final_left(seq, false); + start_left = SEQ_transform_get_left_handle_frame(seq, false); td2d->loc[0] = start_left; tdsq->start_offset = start_left - seq->start; /* use to apply the original location */ break; case SEQ_LEFTSEL: - start_left = BKE_sequence_tx_get_final_left(seq, false); + start_left = SEQ_transform_get_left_handle_frame(seq, false); td2d->loc[0] = start_left; break; case SEQ_RIGHTSEL: - td2d->loc[0] = BKE_sequence_tx_get_final_right(seq, false); + td2d->loc[0] = SEQ_transform_get_right_handle_frame(seq, false); break; } @@ -366,7 +370,7 @@ static void SeqTransDataBounds(TransInfo *t, ListBase *seqbase, TransSeq *ts) static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data) { - Editing *ed = BKE_sequencer_editing_get(t->scene, false); + Editing *ed = SEQ_editing_get(t->scene, false); if (ed != NULL) { @@ -388,7 +392,7 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c for (a = 0; a < t->total; a++, td++) { if ((seq != seq_prev) && (seq->depth == 0) && (seq->flag & SEQ_OVERLAP)) { seq = ((TransDataSeq *)td->extra)->seq; - BKE_sequence_base_shuffle(seqbasep, seq, t->scene); + SEQ_transform_seqbase_shuffle(seqbasep, seq, t->scene); } seq_prev = seq; @@ -429,7 +433,7 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c } else { /* Tag seq with a non zero value, used by - * BKE_sequence_base_shuffle_time to identify the ones to shuffle */ + * SEQ_transform_seqbase_shuffle_time to identify the ones to shuffle */ if (seq->depth == 0) { seq->tmp = (void *)1; } @@ -455,7 +459,7 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c } } - BKE_sequence_base_shuffle_time(seqbasep, t->scene, markers, use_sync_markers); + SEQ_transform_seqbase_shuffle_time(seqbasep, t->scene, markers, use_sync_markers); for (seq = seqbasep->first; seq; seq = seq->next) { if (seq->machine >= MAXSEQ * 2) { @@ -467,10 +471,10 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c } } - BKE_sequence_base_shuffle_time(seqbasep, t->scene, markers, use_sync_markers); + SEQ_transform_seqbase_shuffle_time(seqbasep, t->scene, markers, use_sync_markers); } else { - BKE_sequence_base_shuffle_time(seqbasep, t->scene, markers, use_sync_markers); + SEQ_transform_seqbase_shuffle_time(seqbasep, t->scene, markers, use_sync_markers); } if (has_effect_any) { @@ -480,7 +484,7 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c seq = ((TransDataSeq *)td->extra)->seq; if ((seq != seq_prev)) { if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) { - BKE_sequence_calc(t->scene, seq); + SEQ_time_update_sequence(t->scene, seq); } } } @@ -493,8 +497,8 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c seq = ((TransDataSeq *)td->extra)->seq; if ((seq != seq_prev) && (seq->depth == 0)) { if ((seq->type & SEQ_TYPE_EFFECT) && seq->seq1) { - if (BKE_sequence_test_overlap(seqbasep, seq)) { - BKE_sequence_base_shuffle(seqbasep, seq, t->scene); + if (SEQ_transform_test_overlap(seqbasep, seq)) { + SEQ_transform_seqbase_shuffle(seqbasep, seq, t->scene); } } } @@ -509,18 +513,18 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c /* We might want to build a list of effects that need to be updated during transform */ if (seq->type & SEQ_TYPE_EFFECT) { if (seq->seq1 && seq->seq1->flag & SELECT) { - BKE_sequence_calc(t->scene, seq); + SEQ_time_update_sequence(t->scene, seq); } else if (seq->seq2 && seq->seq2->flag & SELECT) { - BKE_sequence_calc(t->scene, seq); + SEQ_time_update_sequence(t->scene, seq); } else if (seq->seq3 && seq->seq3->flag & SELECT) { - BKE_sequence_calc(t->scene, seq); + SEQ_time_update_sequence(t->scene, seq); } } } - BKE_sequencer_sort(t->scene); + SEQ_sort(t->scene); } else { /* Canceled, need to update the strips display */ @@ -528,10 +532,10 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c seq = ((TransDataSeq *)td->extra)->seq; if ((seq != seq_prev) && (seq->depth == 0)) { if (seq->flag & SEQ_OVERLAP) { - BKE_sequence_base_shuffle(seqbasep, seq, t->scene); + SEQ_transform_seqbase_shuffle(seqbasep, seq, t->scene); } - BKE_sequence_calc_disp(t->scene, seq); + SEQ_time_update_sequence_bounds(t->scene, seq); } seq_prev = seq; } @@ -553,7 +557,7 @@ void createTransSeqData(TransInfo *t) #define XXX_DURIAN_ANIM_TX_HACK Scene *scene = t->scene; - Editing *ed = BKE_sequencer_editing_get(t->scene, false); + Editing *ed = SEQ_editing_get(t->scene, false); TransData *td = NULL; TransData2D *td2d = NULL; TransDataSeq *tdsq = NULL; @@ -640,21 +644,21 @@ BLI_INLINE void trans_update_seq(Scene *sce, Sequence *seq, int old_start, int s /* Calculate this strip and all nested strips. * Children are ALWAYS transformed first so we don't need to do this in another loop. */ - BKE_sequence_calc(sce, seq); + SEQ_time_update_sequence(sce, seq); } else { - BKE_sequence_calc_disp(sce, seq); + SEQ_time_update_sequence_bounds(sce, seq); } if (sel_flag == SELECT) { - BKE_sequencer_offset_animdata(sce, seq, seq->start - old_start); + SEQ_offset_animdata(sce, seq, seq->start - old_start); } } static void flushTransSeq(TransInfo *t) { /* Editing null check already done */ - ListBase *seqbasep = BKE_sequencer_editing_get(t->scene, false)->seqbasep; + ListBase *seqbasep = SEQ_editing_get(t->scene, false)->seqbasep; int a, new_frame; TransData *td = NULL; @@ -681,7 +685,7 @@ static void flushTransSeq(TransInfo *t) switch (tdsq->sel_flag) { case SELECT: #ifdef SEQ_TX_NESTED_METAS - if ((seq->depth != 0 || BKE_sequence_tx_test(seq))) { + if ((seq->depth != 0 || SEQ_transform_sequence_can_be_translated(seq))) { /* for meta's, their children move */ seq->start = new_frame - tdsq->start_offset; } @@ -697,18 +701,18 @@ static void flushTransSeq(TransInfo *t) } break; case SEQ_LEFTSEL: /* no vertical transform */ - BKE_sequence_tx_set_final_left(seq, new_frame); - BKE_sequence_tx_handle_xlimits(seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL); + SEQ_transform_set_left_handle_frame(seq, new_frame); + SEQ_transform_handle_xlimits(seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL); /* todo - move this into aftertrans update? - old seq tx needed it anyway */ - BKE_sequence_single_fix(seq); + SEQ_transform_fix_single_image_seq_offsets(seq); break; case SEQ_RIGHTSEL: /* no vertical transform */ - BKE_sequence_tx_set_final_right(seq, new_frame); - BKE_sequence_tx_handle_xlimits(seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL); + SEQ_transform_set_right_handle_frame(seq, new_frame); + SEQ_transform_handle_xlimits(seq, tdsq->flag & SEQ_LEFTSEL, tdsq->flag & SEQ_RIGHTSEL); /* todo - move this into aftertrans update? - old seq tx needed it anyway */ - BKE_sequence_single_fix(seq); + SEQ_transform_fix_single_image_seq_offsets(seq); break; } @@ -743,12 +747,12 @@ static void flushTransSeq(TransInfo *t) /* calc all meta's then effects T27953. */ for (seq = seqbasep->first; seq; seq = seq->next) { if (seq->type == SEQ_TYPE_META && seq->flag & SELECT) { - BKE_sequence_calc(t->scene, seq); + SEQ_time_update_sequence(t->scene, seq); } } for (seq = seqbasep->first; seq; seq = seq->next) { if (seq->seq1 || seq->seq2 || seq->seq3) { - BKE_sequence_calc(t->scene, seq); + SEQ_time_update_sequence(t->scene, seq); } } @@ -759,7 +763,7 @@ static void flushTransSeq(TransInfo *t) seq = tdsq->seq; if ((seq != seq_prev) && (seq->depth != 0)) { if (seq->seq1 || seq->seq2 || seq->seq3) { - BKE_sequence_calc(t->scene, seq); + SEQ_time_update_sequence(t->scene, seq); } } } @@ -777,7 +781,7 @@ static void flushTransSeq(TransInfo *t) if (seq->depth == 0) { /* test overlap, displays red outline */ seq->flag &= ~SEQ_OVERLAP; - if (BKE_sequence_test_overlap(seqbasep, seq)) { + if (SEQ_transform_test_overlap(seqbasep, seq)) { seq->flag |= SEQ_OVERLAP; } } @@ -800,7 +804,7 @@ void recalcData_sequencer(TransInfo *t) Sequence *seq = tdsq->seq; if (seq != seq_prev) { - BKE_sequence_invalidate_cache_composite(t->scene, seq); + SEQ_relations_invalidate_cache_composite(t->scene, seq); } seq_prev = seq; diff --git a/source/blender/editors/transform/transform_mode_edge_seq_slide.c b/source/blender/editors/transform/transform_mode_edge_seq_slide.c index dfa5c164acf..7ccfd0149bd 100644 --- a/source/blender/editors/transform/transform_mode_edge_seq_slide.c +++ b/source/blender/editors/transform/transform_mode_edge_seq_slide.c @@ -32,6 +32,7 @@ #include "ED_screen.h" #include "WM_api.h" +#include "WM_types.h" #include "UI_interface.h" @@ -45,6 +46,18 @@ /** \name Transform (Sequencer Slide) * \{ */ +static eRedrawFlag seq_slide_handleEvent(struct TransInfo *t, const wmEvent *event) +{ + BLI_assert(t->mode == TFM_SEQ_SLIDE); + wmKeyMapItem *kmi = t->custom.mode.data; + if (kmi && event->type == kmi->type && event->val == kmi->val) { + /* Allows the 'Expand to fit' effect to be enabled as a toogle. */ + t->flag ^= T_ALT_TRANSFORM; + return TREDRAW_HARD; + } + return TREDRAW_NOTHING; +} + static void headerSeqSlide(TransInfo *t, const float val[2], char str[UI_MAX_DRAW_STR]) { char tvec[NUM_STR_REP_LEN * 3]; @@ -60,12 +73,11 @@ static void headerSeqSlide(TransInfo *t, const float val[2], char str[UI_MAX_DRA ofs += BLI_snprintf( str + ofs, UI_MAX_DRAW_STR - ofs, TIP_("Sequence Slide: %s%s, ("), &tvec[0], t->con.text); - if (t->keymap) { - wmKeyMapItem *kmi = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_TRANSLATE); - if (kmi) { - ofs += WM_keymap_item_to_string(kmi, false, str + ofs, UI_MAX_DRAW_STR - ofs); - } + wmKeyMapItem *kmi = t->custom.mode.data; + if (kmi) { + ofs += WM_keymap_item_to_string(kmi, false, str + ofs, UI_MAX_DRAW_STR - ofs); } + ofs += BLI_snprintf(str + ofs, UI_MAX_DRAW_STR - ofs, TIP_(" or Alt) Expand to fit %s"), @@ -91,7 +103,7 @@ static void applySeqSlideValue(TransInfo *t, const float val[2]) static void applySeqSlide(TransInfo *t, const int mval[2]) { char str[UI_MAX_DRAW_STR]; - float values_final[2] = {0.0f}; + float values_final[3] = {0.0f}; snapSequenceBounds(t, mval); if (applyNumInput(&t->num, values_final)) { @@ -126,6 +138,7 @@ static void applySeqSlide(TransInfo *t, const int mval[2]) void initSeqSlide(TransInfo *t) { t->transform = applySeqSlide; + t->handleEvent = seq_slide_handleEvent; initMouseInputMode(t, &t->mouse, INPUT_VECTOR); @@ -142,5 +155,10 @@ void initSeqSlide(TransInfo *t) * (supporting frames in addition to "natural" time...). */ t->num.unit_type[0] = B_UNIT_NONE; t->num.unit_type[1] = B_UNIT_NONE; + + if (t->keymap) { + /* Workaround to use the same key as the modal keymap. */ + t->custom.mode.data = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_TRANSLATE); + } } /** \} */ diff --git a/source/blender/editors/transform/transform_mode_shrink_fatten.c b/source/blender/editors/transform/transform_mode_shrink_fatten.c index cdea388529f..2a5c631df41 100644 --- a/source/blender/editors/transform/transform_mode_shrink_fatten.c +++ b/source/blender/editors/transform/transform_mode_shrink_fatten.c @@ -32,6 +32,7 @@ #include "ED_screen.h" #include "WM_api.h" +#include "WM_types.h" #include "UI_interface.h" @@ -45,6 +46,18 @@ /** \name Transform (Shrink-Fatten) * \{ */ +static eRedrawFlag shrinkfatten_handleEvent(struct TransInfo *t, const wmEvent *event) +{ + BLI_assert(t->mode == TFM_SHRINKFATTEN); + wmKeyMapItem *kmi = t->custom.mode.data; + if (kmi && event->type == kmi->type && event->val == kmi->val) { + /* Allows the 'Even Thickness' effect to be enabled as a toogle. */ + t->flag ^= T_ALT_TRANSFORM; + return TREDRAW_HARD; + } + return TREDRAW_NOTHING; +} + static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) { float distance; @@ -77,12 +90,11 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) } ofs += BLI_strncpy_rlen(str + ofs, ", (", sizeof(str) - ofs); - if (t->keymap) { - wmKeyMapItem *kmi = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_RESIZE); - if (kmi) { - ofs += WM_keymap_item_to_string(kmi, false, str + ofs, sizeof(str) - ofs); - } + wmKeyMapItem *kmi = t->custom.mode.data; + if (kmi) { + ofs += WM_keymap_item_to_string(kmi, false, str + ofs, sizeof(str) - ofs); } + BLI_snprintf(str + ofs, sizeof(str) - ofs, TIP_(" or Alt) Even Thickness %s"), @@ -121,6 +133,7 @@ void initShrinkFatten(TransInfo *t) else { t->mode = TFM_SHRINKFATTEN; t->transform = applyShrinkFatten; + t->handleEvent = shrinkfatten_handleEvent; initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE); @@ -134,6 +147,11 @@ void initShrinkFatten(TransInfo *t) t->num.unit_type[0] = B_UNIT_LENGTH; t->flag |= T_NO_CONSTRAINT; + + if (t->keymap) { + /* Workaround to use the same key as the modal keymap. */ + t->custom.mode.data = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_RESIZE); + } } } /** \} */ diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c index 90c1f241338..8597c372537 100644 --- a/source/blender/editors/transform/transform_mode_translate.c +++ b/source/blender/editors/transform/transform_mode_translate.c @@ -377,6 +377,9 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2])) else { mul_v3_m3v3(global_dir, t->spacemtx, global_dir); } + if (t->flag & T_2D_EDIT) { + removeAspectRatio(t, global_dir); + } } else { copy_v3_v3(global_dir, t->values); diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 5153fdedcae..5d758a6c6c6 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -717,7 +717,7 @@ void Transform_Properties(struct wmOperatorType *ot, int flags) "use_automerge_and_split", 0, "Auto Merge & Split", - "Forces the use of Auto Merge & Split"); + "Forces the use of Auto Merge and Split"); RNA_def_property_flag(prop, PROP_HIDDEN); } } diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index f1c4c243780..d407cea0033 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -42,6 +42,7 @@ #include "RNA_access.h" #include "SEQ_sequencer.h" +#include "SEQ_time.h" #include "WM_types.h" @@ -1409,7 +1410,7 @@ void snapSequenceBounds(TransInfo *t, const int mval[2]) const int frame_curr = round_fl_to_int(xmouse); /* Now find the closest sequence. */ - const int frame_near = BKE_sequencer_find_next_prev_edit( + const int frame_near = SEQ_time_find_next_prev_edit( t->scene, frame_curr, SEQ_SIDE_BOTH, true, false, true); const int frame_snap = transform_convert_sequencer_get_snap_bound(t); diff --git a/source/blender/editors/transform/transform_snap.h b/source/blender/editors/transform/transform_snap.h index 5bee572c603..db8ec943bfd 100644 --- a/source/blender/editors/transform/transform_snap.h +++ b/source/blender/editors/transform/transform_snap.h @@ -25,8 +25,6 @@ /* For enum. */ #include "DNA_space_types.h" -struct SnapObjectParams; - bool peelObjectsTransform(struct TransInfo *t, const float mval[2], const bool use_peel_object, diff --git a/source/blender/editors/undo/memfile_undo.c b/source/blender/editors/undo/memfile_undo.c index 49417a54472..4fded419b5b 100644 --- a/source/blender/editors/undo/memfile_undo.c +++ b/source/blender/editors/undo/memfile_undo.c @@ -27,6 +27,7 @@ #include "BLI_listbase.h" #include "DNA_ID.h" +#include "DNA_collection_types.h" #include "DNA_node_types.h" #include "DNA_object_enums.h" #include "DNA_object_types.h" diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt index c88169778f7..0aab3810254 100644 --- a/source/blender/editors/util/CMakeLists.txt +++ b/source/blender/editors/util/CMakeLists.txt @@ -39,6 +39,7 @@ set(SRC ed_transverts.c ed_util.c ed_util_imbuf.c + ed_util_ops.c gizmo_utils.c numinput.c select_utils.c @@ -47,6 +48,7 @@ set(SRC ../include/BIF_glutil.h ../include/ED_anim_api.h ../include/ED_armature.h + ../include/ED_asset.h ../include/ED_buttons.h ../include/ED_clip.h ../include/ED_curve.h diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c index 76c261c9cba..5d2584c566d 100644 --- a/source/blender/editors/util/ed_util.c +++ b/source/blender/editors/util/ed_util.c @@ -35,6 +35,7 @@ #include "DNA_screen_types.h" #include "DNA_space_types.h" +#include "BLI_fileops.h" #include "BLI_listbase.h" #include "BLI_path_util.h" #include "BLI_string.h" @@ -44,6 +45,7 @@ #include "BKE_context.h" #include "BKE_global.h" +#include "BKE_icons.h" #include "BKE_layer.h" #include "BKE_main.h" #include "BKE_material.h" @@ -51,6 +53,7 @@ #include "BKE_object.h" #include "BKE_packedFile.h" #include "BKE_paint.h" +#include "BKE_report.h" #include "BKE_screen.h" #include "BKE_undo_system.h" #include "BKE_workspace.h" @@ -64,6 +67,7 @@ #include "ED_object.h" #include "ED_outliner.h" #include "ED_paint.h" +#include "ED_render.h" #include "ED_space_api.h" #include "ED_util.h" @@ -481,22 +485,102 @@ void ED_spacedata_id_remap(struct ScrArea *area, struct SpaceLink *sl, ID *old_i } } -static int ed_flush_edits_exec(bContext *C, wmOperator *UNUSED(op)) +static bool lib_id_preview_editing_poll(bContext *C) { - Main *bmain = CTX_data_main(C); - ED_editors_flush_edits(bmain); + const PointerRNA idptr = CTX_data_pointer_get(C, "id"); + BLI_assert(!idptr.data || RNA_struct_is_ID(idptr.type)); + + const ID *id = idptr.data; + if (!id) { + return false; + } + if (ID_IS_LINKED(id)) { + CTX_wm_operator_poll_msg_set(C, TIP_("Can't edit external library data")); + return false; + } + if (ID_IS_OVERRIDE_LIBRARY(id)) { + CTX_wm_operator_poll_msg_set(C, TIP_("Can't edit previews of overridden library data")); + return false; + } + if (!BKE_previewimg_id_get_p(id)) { + CTX_wm_operator_poll_msg_set(C, TIP_("Data-block does not support previews")); + return false; + } + + return true; +} + +static int lib_id_load_custom_preview_exec(bContext *C, wmOperator *op) +{ + char path[FILE_MAX]; + + RNA_string_get(op->ptr, "filepath", path); + + if (!BLI_is_file(path)) { + BKE_reportf(op->reports, RPT_ERROR, "File not found '%s'", path); + return OPERATOR_CANCELLED; + } + + PointerRNA idptr = CTX_data_pointer_get(C, "id"); + ID *id = idptr.data; + + BKE_previewimg_id_custom_set(id, path); + + WM_event_add_notifier(C, NC_ASSET, NULL); + + return OPERATOR_FINISHED; +} + +void ED_OT_lib_id_load_custom_preview(wmOperatorType *ot) +{ + ot->name = "Load Custom Preview"; + ot->description = "Choose an image to help identify the data-block visually"; + ot->idname = "ED_OT_lib_id_load_custom_preview"; + + /* api callbacks */ + ot->poll = lib_id_preview_editing_poll; + ot->exec = lib_id_load_custom_preview_exec; + ot->invoke = WM_operator_filesel; + + /* flags */ + ot->flag = OPTYPE_INTERNAL; + + WM_operator_properties_filesel(ot, + FILE_TYPE_FOLDER | FILE_TYPE_IMAGE, + FILE_SPECIAL, + FILE_OPENFILE, + WM_FILESEL_FILEPATH, + FILE_DEFAULTDISPLAY, + FILE_SORT_DEFAULT); +} + +static int lib_id_generate_preview_exec(bContext *C, wmOperator *UNUSED(op)) +{ + PointerRNA idptr = CTX_data_pointer_get(C, "id"); + ID *id = idptr.data; + + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); + + PreviewImage *preview = BKE_previewimg_id_get(id); + if (preview) { + BKE_previewimg_clear(preview); + } + UI_icon_render_id(C, NULL, id, true, true); + + WM_event_add_notifier(C, NC_ASSET, NULL); + return OPERATOR_FINISHED; } -void ED_OT_flush_edits(wmOperatorType *ot) +void ED_OT_lib_id_generate_preview(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Flush Edits"; - ot->description = "Flush edit data from active editing modes"; - ot->idname = "ED_OT_flush_edits"; + ot->name = "Generate Preview"; + ot->description = "Create an automatic preview for the selected data-block"; + ot->idname = "ED_OT_lib_id_generate_preview"; /* api callbacks */ - ot->exec = ed_flush_edits_exec; + ot->poll = lib_id_preview_editing_poll; + ot->exec = lib_id_generate_preview_exec; /* flags */ ot->flag = OPTYPE_INTERNAL; diff --git a/source/blender/editors/util/ed_util_imbuf.c b/source/blender/editors/util/ed_util_imbuf.c index b832d9a1d86..0f2e280251f 100644 --- a/source/blender/editors/util/ed_util_imbuf.c +++ b/source/blender/editors/util/ed_util_imbuf.c @@ -42,6 +42,7 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" +#include "SEQ_render.h" #include "SEQ_sequencer.h" #include "UI_view2d.h" @@ -564,7 +565,7 @@ bool ED_imbuf_sample_poll(bContext *C) return false; } - return sseq && BKE_sequencer_editing_get(CTX_data_scene(C), false) != NULL; + return sseq && SEQ_editing_get(CTX_data_scene(C), false) != NULL; } return false; diff --git a/source/blender/editors/util/ed_util_ops.c b/source/blender/editors/util/ed_util_ops.c new file mode 100644 index 00000000000..d8d1a64c1ee --- /dev/null +++ b/source/blender/editors/util/ed_util_ops.c @@ -0,0 +1,155 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup edutil + * + * Utility operators for UI data or for the UI to use. + */ + +#include <string.h> + +#include "BLI_utildefines.h" + +#include "BKE_context.h" +#include "BKE_lib_id.h" +#include "BKE_main.h" +#include "BKE_report.h" + +#include "DNA_windowmanager_types.h" + +#include "ED_util.h" + +#include "RNA_access.h" + +#include "UI_interface.h" + +#include "WM_api.h" +#include "WM_types.h" + +static int lib_fake_user_toggle_exec(bContext *C, wmOperator *op) +{ + PropertyPointerRNA pprop; + PointerRNA idptr = PointerRNA_NULL; + + UI_context_active_but_prop_get_templateID(C, &pprop.ptr, &pprop.prop); + + if (pprop.prop) { + idptr = RNA_property_pointer_get(&pprop.ptr, pprop.prop); + } + + if ((pprop.prop == NULL) || RNA_pointer_is_null(&idptr) || !RNA_struct_is_ID(idptr.type)) { + BKE_report( + op->reports, RPT_ERROR, "Incorrect context for running data-block fake user toggling"); + return OPERATOR_CANCELLED; + } + + ID *id = idptr.data; + + if ((id->lib != NULL) || (ELEM(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_TXT, ID_OB, ID_WS))) { + BKE_report(op->reports, RPT_ERROR, "Data-block type does not support fake user"); + return OPERATOR_CANCELLED; + } + + if (ID_FAKE_USERS(id)) { + id_fake_user_clear(id); + } + else { + id_fake_user_set(id); + } + + return OPERATOR_FINISHED; +} + +static void ED_OT_lib_fake_user_toggle(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Toggle Fake User"; + ot->description = "Save this data-block even if it has no users"; + ot->idname = "ED_OT_lib_fake_user_toggle"; + + /* api callbacks */ + ot->exec = lib_fake_user_toggle_exec; + + /* flags */ + ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; +} + +static int lib_unlink_exec(bContext *C, wmOperator *op) +{ + PropertyPointerRNA pprop; + PointerRNA idptr; + + UI_context_active_but_prop_get_templateID(C, &pprop.ptr, &pprop.prop); + + if (pprop.prop) { + idptr = RNA_property_pointer_get(&pprop.ptr, pprop.prop); + } + + if ((pprop.prop == NULL) || RNA_pointer_is_null(&idptr) || !RNA_struct_is_ID(idptr.type)) { + BKE_report( + op->reports, RPT_ERROR, "Incorrect context for running data-block fake user toggling"); + return OPERATOR_CANCELLED; + } + + memset(&idptr, 0, sizeof(idptr)); + RNA_property_pointer_set(&pprop.ptr, pprop.prop, idptr, NULL); + RNA_property_update(C, &pprop.ptr, pprop.prop); + + return OPERATOR_FINISHED; +} + +static void ED_OT_lib_unlink(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Unlink Data-Block"; + ot->description = "Remove a usage of a data-block, clearing the assignment"; + ot->idname = "ED_OT_lib_unlink"; + + /* api callbacks */ + ot->exec = lib_unlink_exec; + + /* flags */ + ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; +} + +static int ed_flush_edits_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Main *bmain = CTX_data_main(C); + ED_editors_flush_edits(bmain); + return OPERATOR_FINISHED; +} + +static void ED_OT_flush_edits(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Flush Edits"; + ot->description = "Flush edit data from active editing modes"; + ot->idname = "ED_OT_flush_edits"; + + /* api callbacks */ + ot->exec = ed_flush_edits_exec; + + /* flags */ + ot->flag = OPTYPE_INTERNAL; +} + +void ED_operatortypes_edutils(void) +{ + WM_operatortype_append(ED_OT_lib_fake_user_toggle); + WM_operatortype_append(ED_OT_lib_unlink); + WM_operatortype_append(ED_OT_flush_edits); +} diff --git a/source/blender/editors/uvedit/CMakeLists.txt b/source/blender/editors/uvedit/CMakeLists.txt index 8e4a3df920e..1c8a56e0608 100644 --- a/source/blender/editors/uvedit/CMakeLists.txt +++ b/source/blender/editors/uvedit/CMakeLists.txt @@ -35,11 +35,11 @@ set(INC set(SRC uvedit_buttons.c uvedit_draw.c + uvedit_islands.c uvedit_ops.c uvedit_parametrizer.c uvedit_path.c uvedit_rip.c - uvedit_islands.c uvedit_select.c uvedit_smart_stitch.c uvedit_unwrap_ops.c diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h index 306f8a2c561..28567234fab 100644 --- a/source/blender/editors/uvedit/uvedit_intern.h +++ b/source/blender/editors/uvedit/uvedit_intern.h @@ -25,7 +25,6 @@ struct BMFace; struct BMLoop; -struct Image; struct Object; struct Scene; struct SpaceImage; diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 5b3d858329a..aac5b96f737 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -1812,7 +1812,7 @@ static void UV_OT_cursor_set(wmOperatorType *ot) -FLT_MAX, FLT_MAX, "Location", - "Cursor location in normalized (0.0-1.0) coordinates", + "Cursor location in normalized (0.0 to 1.0) coordinates", -10.0f, 10.0f); } diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c index 6dac31794b4..c1d222c9368 100644 --- a/source/blender/editors/uvedit/uvedit_smart_stitch.c +++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c @@ -2808,7 +2808,7 @@ void UV_OT_stitch(wmOperatorType *ot) RNA_def_boolean(ot->srna, "midpoint_snap", 0, - "Snap At Midpoint", + "Snap at Midpoint", "UVs are stitched at midpoint instead of at static island"); RNA_def_boolean(ot->srna, "clear_seams", 1, "Clear Seams", "Clear seams of stitched edges"); RNA_def_enum(ot->srna, diff --git a/source/blender/freestyle/intern/application/Controller.cpp b/source/blender/freestyle/intern/application/Controller.cpp index e24700a57d8..ddd11729e67 100644 --- a/source/blender/freestyle/intern/application/Controller.cpp +++ b/source/blender/freestyle/intern/application/Controller.cpp @@ -1067,7 +1067,7 @@ void Controller::displayDensityCurves(int x, int y) } unsigned int i, j; - typedef vector<Vec3r> densityCurve; + using densityCurve = vector<Vec3r>; vector<densityCurve> curves(svm->getNumberOfOrientations() + 1); vector<densityCurve> curvesDirection(svm->getNumberOfPyramidLevels()); diff --git a/source/blender/freestyle/intern/geometry/FitCurve.cpp b/source/blender/freestyle/intern/geometry/FitCurve.cpp index 66914929960..5768f88e95f 100644 --- a/source/blender/freestyle/intern/geometry/FitCurve.cpp +++ b/source/blender/freestyle/intern/geometry/FitCurve.cpp @@ -30,7 +30,7 @@ using namespace std; namespace Freestyle { -typedef Vector2 *BezierCurve; +using BezierCurve = Vector2 *; /* Forward declarations */ static double *Reparameterize(Vector2 *d, int first, int last, double *u, BezierCurve bezCurve); diff --git a/source/blender/freestyle/intern/geometry/GeomCleaner.cpp b/source/blender/freestyle/intern/geometry/GeomCleaner.cpp index 6a499c07061..7ec18fb2801 100644 --- a/source/blender/freestyle/intern/geometry/GeomCleaner.cpp +++ b/source/blender/freestyle/intern/geometry/GeomCleaner.cpp @@ -202,7 +202,7 @@ void GeomCleaner::CleanIndexedVertexArray(const float *iVertices, unsigned *oVSize, unsigned **oIndices) { - typedef map<Vec3f, unsigned> cleanHashTable; + using cleanHashTable = map<Vec3f, unsigned>; vector<Vec3f> vertices; unsigned i; for (i = 0; i < iVSize; i += 3) { diff --git a/source/blender/functions/FN_generic_pointer.hh b/source/blender/functions/FN_generic_pointer.hh index 5c2b611c614..2bd66daa7fe 100644 --- a/source/blender/functions/FN_generic_pointer.hh +++ b/source/blender/functions/FN_generic_pointer.hh @@ -21,7 +21,7 @@ namespace blender::fn { /** - * A generic pointer whose type is only known at runtime. + * A generic non-const pointer whose type is only known at runtime. */ class GMutablePointer { private: @@ -58,7 +58,7 @@ class GMutablePointer { template<typename T> T *get() const { BLI_assert(this->is_type<T>()); - return reinterpret_cast<T *>(data_); + return static_cast<T *>(data_); } template<typename T> bool is_type() const @@ -73,4 +73,55 @@ class GMutablePointer { } }; +/** + * A generic const pointer whose type is only known at runtime. + */ +class GPointer { + private: + const CPPType *type_ = nullptr; + const void *data_ = nullptr; + + public: + GPointer() = default; + + GPointer(GMutablePointer ptr) : type_(ptr.type()), data_(ptr.get()) + { + } + + GPointer(const CPPType *type, const void *data = nullptr) : type_(type), data_(data) + { + /* If there is data, there has to be a type. */ + BLI_assert(data_ == nullptr || type_ != nullptr); + } + + GPointer(const CPPType &type, const void *data = nullptr) : type_(&type), data_(data) + { + } + + template<typename T> GPointer(T *data) : GPointer(&CPPType::get<T>(), data) + { + } + + const void *get() const + { + return data_; + } + + const CPPType *type() const + { + return type_; + } + + template<typename T> const T *get() const + { + BLI_assert(this->is_type<T>()); + return static_cast<const T *>(data_); + } + + template<typename T> bool is_type() const + { + return type_ != nullptr && type_->is<T>(); + } +}; + } // namespace blender::fn diff --git a/source/blender/functions/FN_generic_value_map.hh b/source/blender/functions/FN_generic_value_map.hh index 2c1b37c0461..a9f2dc8a868 100644 --- a/source/blender/functions/FN_generic_value_map.hh +++ b/source/blender/functions/FN_generic_value_map.hh @@ -66,7 +66,7 @@ template<typename Key> class GValueMap { /* Add a value to the container that is copy constructed from the given value. The caller remains * responsible for destructing and freeing the given value. */ - template<typename ForwardKey> void add_new_by_copy(ForwardKey &&key, GMutablePointer value) + template<typename ForwardKey> void add_new_by_copy(ForwardKey &&key, GPointer value) { const CPPType &type = *value.type(); void *buffer = allocator_.allocate(type.size(), type.alignment()); diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c index 37cde3162a0..d3ba5bf8b37 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c @@ -28,6 +28,7 @@ #include "BKE_object.h" #include "BKE_screen.h" +#include "DNA_material_types.h" #include "DNA_object_force_types.h" #include "DNA_object_types.h" #include "DNA_particle_types.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c index 077a454db73..f5bfe66562b 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c @@ -33,6 +33,7 @@ #include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" +#include "DNA_material_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h index e5a6d9e6a8f..30e54f44499 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h @@ -23,9 +23,7 @@ #pragma once -struct GHash; struct MDeformVert; -struct Main; struct Material; struct Object; struct bGPDlayer; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c index aa21bf192c4..b8fa88327fc 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c @@ -237,9 +237,17 @@ static void generate_geometry(GpencilModifierData *md, /* To ensure a nice distribution, we use halton sequence and offset using the seed. */ BLI_halton_3d(primes, offset, x, r); - for (int i = 0; i < 3; i++) { - rand[j][i] = fmodf(r[i] * 2.0 - 1.0 + rand_offset, 1.0f); - rand[j][i] = fmodf(sin(rand[j][i] * 12.9898 + j * 78.233) * 43758.5453, 1.0f); + if ((mmd->flag & GP_ARRAY_UNIFORM_RANDOM_SCALE) && j == 2) { + float rand_value; + rand_value = fmodf(r[0] * 2.0 - 1.0 + rand_offset, 1.0f); + rand_value = fmodf(sin(rand_value * 12.9898 + j * 78.233) * 43758.5453, 1.0f); + copy_v3_fl(rand[j], rand_value); + } + else { + for (int i = 0; i < 3; i++) { + rand[j][i] = fmodf(r[i] * 2.0 - 1.0 + rand_offset, 1.0f); + rand[j][i] = fmodf(sin(rand[j][i] * 12.9898 + j * 78.233) * 43758.5453, 1.0f); + } } } /* Calculate Random matrix. */ @@ -425,6 +433,7 @@ static void random_panel_draw(const bContext *UNUSED(C), Panel *panel) uiItemR(layout, ptr, "random_offset", 0, IFACE_("Offset"), ICON_NONE); uiItemR(layout, ptr, "random_rotation", 0, IFACE_("Rotation"), ICON_NONE); uiItemR(layout, ptr, "random_scale", 0, IFACE_("Scale"), ICON_NONE); + uiItemR(layout, ptr, "use_uniform_random_scale", 0, NULL, ICON_NONE); uiItemR(layout, ptr, "seed", 0, NULL, ICON_NONE); } diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c index 4e569099461..04405fed7d9 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c @@ -34,6 +34,7 @@ #include "DNA_defaults.h" #include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" +#include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c index 2ee148837cd..311d08238b9 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c @@ -33,6 +33,7 @@ #include "DNA_defaults.h" #include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" +#include "DNA_material_types.h" #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index 27a7ea1e6a5..55716b584c3 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -27,8 +27,6 @@ extern "C" { #endif -struct GPUTexture; -struct GPUUniformBuf; struct GPUVertBuf; /** Opaque type hidding blender::gpu::Shader */ diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index e9c081abd22..91119bd05a1 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -28,14 +28,6 @@ #include "GPU_state.h" struct GPUVertBuf; -struct ImBuf; -struct Image; -struct ImageUser; -struct MovieClip; -struct MovieClipUser; -struct PreviewImage; - -struct GPUFrameBuffer; /** Opaque type hiding blender::gpu::Texture. */ typedef struct GPUTexture GPUTexture; diff --git a/source/blender/gpu/intern/gpu_batch.cc b/source/blender/gpu/intern/gpu_batch.cc index 08b2e3c0f00..9dc24c59e22 100644 --- a/source/blender/gpu/intern/gpu_batch.cc +++ b/source/blender/gpu/intern/gpu_batch.cc @@ -81,7 +81,7 @@ void GPU_batch_init_ex(GPUBatch *batch, for (int v = 1; v < GPU_BATCH_VBO_MAX_LEN; v++) { batch->verts[v] = nullptr; } - for (auto & v : batch->inst) { + for (auto &v : batch->inst) { v = nullptr; } batch->elem = elem; diff --git a/source/blender/gpu/intern/gpu_codegen.h b/source/blender/gpu/intern/gpu_codegen.h index 5d130d75d2c..f3d58a55814 100644 --- a/source/blender/gpu/intern/gpu_codegen.h +++ b/source/blender/gpu/intern/gpu_codegen.h @@ -31,10 +31,7 @@ extern "C" { struct GPUMaterial; struct GPUNodeGraph; -struct GPUOutput; struct GPUShader; -struct GSet; -struct ListBase; typedef struct GPUPass { struct GPUPass *next; diff --git a/source/blender/gpu/intern/gpu_node_graph.h b/source/blender/gpu/intern/gpu_node_graph.h index 0ef95d94c0d..929191cff73 100644 --- a/source/blender/gpu/intern/gpu_node_graph.h +++ b/source/blender/gpu/intern/gpu_node_graph.h @@ -33,8 +33,6 @@ struct GPUNode; struct GPUOutput; -struct GPUShader; -struct GPUVertAttrLayers; struct ListBase; typedef enum eGPUDataSource { diff --git a/source/blender/gpu/intern/gpu_uniform_buffer_private.hh b/source/blender/gpu/intern/gpu_uniform_buffer_private.hh index 00d10776864..18ea6d18caf 100644 --- a/source/blender/gpu/intern/gpu_uniform_buffer_private.hh +++ b/source/blender/gpu/intern/gpu_uniform_buffer_private.hh @@ -24,6 +24,8 @@ #include "BLI_sys_types.h" +struct GPUUniformBuf; + namespace blender { namespace gpu { diff --git a/source/blender/gpu/intern/gpu_vertex_format.cc b/source/blender/gpu/intern/gpu_vertex_format.cc index cd6d78a185d..014c70033fc 100644 --- a/source/blender/gpu/intern/gpu_vertex_format.cc +++ b/source/blender/gpu/intern/gpu_vertex_format.cc @@ -262,13 +262,12 @@ void GPU_vertformat_attr_rename(GPUVertFormat *format, int attr_id, const char * /* Encode 8 original bytes into 11 safe bytes. */ static void safe_bytes(char out[11], const char data[8]) { - char safe_chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; + char safe_chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; uint64_t in = *(uint64_t *)data; for (int i = 0; i < 11; i++) { - /* Encoding in base63 */ - out[i] = safe_chars[in % 63lu]; - in /= 63lu; + out[i] = safe_chars[in % 62lu]; + in /= 62lu; } } diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c index 188c8786665..a83654d31e7 100644 --- a/source/blender/gpu/intern/gpu_viewport.c +++ b/source/blender/gpu/intern/gpu_viewport.c @@ -616,8 +616,8 @@ void GPU_viewport_stereo_composite(GPUViewport *viewport, Stereo3dFormat *stereo GPU_framebuffer_ensure_config(&dfbl->stereo_comp_fb, { GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(dtxl->color), GPU_ATTACHMENT_TEXTURE(dtxl->color_overlay), + GPU_ATTACHMENT_TEXTURE(dtxl->color), }); GPUVertFormat *vert_format = immVertexFormat(); @@ -628,8 +628,8 @@ void GPU_viewport_stereo_composite(GPUViewport *viewport, Stereo3dFormat *stereo GPU_matrix_identity_set(); GPU_matrix_identity_projection_set(); immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_OVERLAYS_STEREO_MERGE); - immUniform1i("imageTexture", 0); - immUniform1i("overlayTexture", 1); + immUniform1i("overlayTexture", 0); + immUniform1i("imageTexture", 1); int settings = stereo_format->display_mode; if (settings == S3D_DISPLAY_ANAGLYPH) { switch (stereo_format->anaglyph_type) { diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc index 7e948149a7f..f683a70b4e6 100644 --- a/source/blender/gpu/opengl/gl_backend.cc +++ b/source/blender/gpu/opengl/gl_backend.cc @@ -131,19 +131,11 @@ void GLBackend::platform_init() } } - /* Since Blender 2.91 AMD TeraScale 2 GPUs crashes during startup. */ - if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_WIN, GPU_DRIVER_ANY)) { - if (strstr(renderer, "Radeon HD 4") || strstr(renderer, "Radeon HD 5") || - strstr(renderer, "Radeon HD 6") || strstr(renderer, "ATI FirePro V4") || - strstr(renderer, "AMD Radeon R5 2")) { - GPG.support_level = GPU_SUPPORT_LEVEL_UNSUPPORTED; - } - } - /* Driver 20.11.2 fixes a lot of issues for the Navi cards, but introduces new ones + /* Driver 20.11.2/3 fixes a lot of issues for the Navi cards, but introduces new ones * for Polaris based cards cards. The viewport has glitches but doesn't crash. - * See T82856 */ + * See T82856,T83574. */ if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_WIN, GPU_DRIVER_OFFICIAL) && - strstr(version, " 20.11.2 ")) { + (strstr(version, " 20.11.2 ") || strstr(version, " 20.11.3 "))) { if (strstr(renderer, "Radeon RX 460 ") || strstr(renderer, "Radeon RX 470 ") || strstr(renderer, "Radeon RX 480 ") || strstr(renderer, "Radeon RX 490 ") || strstr(renderer, "Radeon RX 560 ") || strstr(renderer, "Radeon RX 570 ") || @@ -152,8 +144,10 @@ void GLBackend::platform_init() } } if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_ANY)) { + /* Platform seems to work when SB backend is disabled. This can be done + * by adding the environment variable `R600_DEBUG=nosb`. */ if (strstr(renderer, "AMD CEDAR")) { - GPG.support_level = GPU_SUPPORT_LEVEL_UNSUPPORTED; + GPG.support_level = GPU_SUPPORT_LEVEL_LIMITED; } } } @@ -253,10 +247,6 @@ static void detect_workarounds() return; } - /* Some Intel drivers have issues with using mips as framebuffer targets if - * GL_TEXTURE_MAX_LEVEL is higher than the target mip. - * Only check at the end after all other workarounds because this uses the drawing code. */ - GCaps.mip_render_workaround = detect_mip_render_workaround(); /* Limit support for GLEW_ARB_base_instance to OpenGL 4.0 and higher. NVIDIA Quadro FX 4800 * (TeraScale) report that they support GLEW_ARB_base_instance, but the driver does not support * GLEW_ARB_draw_indirect as it has an OpenGL3 context what also matches the minimum needed @@ -277,6 +267,7 @@ static void detect_workarounds() (strstr(version, "4.5.13399") || strstr(version, "4.5.13417") || strstr(version, "4.5.13422"))) { GLContext::unused_fb_slot_workaround = true; + GCaps.mip_render_workaround = true; GCaps.shader_image_load_store_support = false; GCaps.broken_amd_driver = true; } @@ -368,6 +359,13 @@ static void detect_workarounds() } } + /* Some Intel drivers have issues with using mips as framebuffer targets if + * GL_TEXTURE_MAX_LEVEL is higher than the target mip. + * Only check at the end after all other workarounds because this uses the drawing code. + * Also after device/driver flags to avoid the check that causes pre GCN Radeon to crash. */ + if (GCaps.mip_render_workaround == false) { + GCaps.mip_render_workaround = detect_mip_render_workaround(); + } /* Disable multidraw if the base instance cannot be read. */ if (GLContext::shader_draw_parameters_support == false) { GLContext::multi_draw_indirect_support = false; diff --git a/source/blender/gpu/opengl/gl_debug_layer.cc b/source/blender/gpu/opengl/gl_debug_layer.cc index 9c2b6c0e547..7d2abfb2cff 100644 --- a/source/blender/gpu/opengl/gl_debug_layer.cc +++ b/source/blender/gpu/opengl/gl_debug_layer.cc @@ -30,7 +30,7 @@ #include "gl_debug.hh" -typedef void *GPUvoidptr; +using GPUvoidptr = void *; #define GPUvoidptr_set void *ret = #define GPUvoidptr_ret return ret diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_clamp.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_clamp.glsl index b196aed690f..f89608feff1 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_clamp.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_clamp.glsl @@ -3,6 +3,11 @@ void clamp_value(float value, float min, float max, out float result) result = clamp(value, min, max); } +void clamp_minmax(float value, float min_allowed, float max_allowed, out float result) +{ + result = min(max(value, min_allowed), max_allowed); +} + void clamp_range(float value, float min, float max, out float result) { result = (max > min) ? clamp(value, min, max) : clamp(value, max, min); diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp index c91da839d25..9512bce1914 100644 --- a/source/blender/ikplugin/intern/itasc_plugin.cpp +++ b/source/blender/ikplugin/intern/itasc_plugin.cpp @@ -76,9 +76,9 @@ struct IK_Data { using Vector3 = float[3]; using Vector4 = float[4]; struct IK_Target; -typedef void (*ErrorCallback)(const iTaSC::ConstraintValues *values, - unsigned int nvalues, - IK_Target *iktarget); +using ErrorCallback = void (*)(const iTaSC::ConstraintValues *values, + unsigned int nvalues, + IK_Target *iktarget); /* one structure for each target in the scene */ struct IK_Target { diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index 957352595ed..58ddc918f61 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -382,6 +382,8 @@ bool IMB_anim_can_produce_frames(const struct anim *anim); int ismovie(const char *filepath); void IMB_anim_set_preseek(struct anim *anim, int preseek); int IMB_anim_get_preseek(struct anim *anim); +int IMB_anim_get_image_width(struct anim *anim); +int IMB_anim_get_image_height(struct anim *anim); /** * diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index d825b20f5f2..9b01ea0840f 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -1506,3 +1506,13 @@ int IMB_anim_get_preseek(struct anim *anim) { return anim->preseek; } + +int IMB_anim_get_image_width(struct anim *anim) +{ + return anim->x; +} + +int IMB_anim_get_image_height(struct anim *anim) +{ + return anim->y; +} diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c index 2c95d49612f..046e233fd05 100644 --- a/source/blender/imbuf/intern/colormanagement.c +++ b/source/blender/imbuf/intern/colormanagement.c @@ -57,7 +57,7 @@ #include "RNA_define.h" -#include "SEQ_sequencer.h" +#include "SEQ_iterator.h" #include <ocio_capi.h> diff --git a/source/blender/imbuf/intern/dds/FlipDXT.cpp b/source/blender/imbuf/intern/dds/FlipDXT.cpp index e96b7891f1e..2acf072556a 100644 --- a/source/blender/imbuf/intern/dds/FlipDXT.cpp +++ b/source/blender/imbuf/intern/dds/FlipDXT.cpp @@ -45,7 +45,7 @@ #include <Stream.h> /* A function that flips a DXTC block. */ -typedef void (*FlipBlockFunction)(uint8_t *block); +using FlipBlockFunction = void (*)(uint8_t *block); /* Flips a full DXT1 block in the y direction. */ static void FlipDXT1BlockFull(uint8_t *block) diff --git a/source/blender/imbuf/intern/jpeg.c b/source/blender/imbuf/intern/jpeg.c index 93cdbbb1407..7d4797def8f 100644 --- a/source/blender/imbuf/intern/jpeg.c +++ b/source/blender/imbuf/intern/jpeg.c @@ -33,6 +33,8 @@ #include "BKE_idprop.h" +#include "DNA_ID.h" /* ID property definitions. */ + #include "IMB_filetype.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" diff --git a/source/blender/imbuf/intern/metadata.c b/source/blender/imbuf/intern/metadata.c index 28f09c38a96..d8abd3411cb 100644 --- a/source/blender/imbuf/intern/metadata.c +++ b/source/blender/imbuf/intern/metadata.c @@ -29,6 +29,8 @@ #include "BKE_idprop.h" +#include "DNA_ID.h" /* ID property definitions. */ + #include "MEM_guardedalloc.h" #include "IMB_imbuf.h" diff --git a/source/blender/imbuf/intern/oiio/openimageio_api.cpp b/source/blender/imbuf/intern/oiio/openimageio_api.cpp index 1e8c3c25778..65c25194477 100644 --- a/source/blender/imbuf/intern/oiio/openimageio_api.cpp +++ b/source/blender/imbuf/intern/oiio/openimageio_api.cpp @@ -48,7 +48,7 @@ OIIO_NAMESPACE_USING using std::string; using std::unique_ptr; -typedef unsigned char uchar; +using uchar = unsigned char; template<class T, class Q> static void fill_all_channels(T *pixels, int width, int height, int components, Q alpha) diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index 12faa48c81c..9726eaeed2c 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -322,7 +322,7 @@ struct _RGBAZ { half z; }; -typedef struct _RGBAZ RGBAZ; +using RGBAZ = _RGBAZ; extern "C" { diff --git a/source/blender/imbuf/intern/png.c b/source/blender/imbuf/intern/png.c index 60fc2ac0867..561a833803d 100644 --- a/source/blender/imbuf/intern/png.c +++ b/source/blender/imbuf/intern/png.c @@ -32,6 +32,8 @@ #include "BKE_global.h" #include "BKE_idprop.h" +#include "DNA_ID.h" /* ID property definitions. */ + #include "MEM_guardedalloc.h" #include "IMB_imbuf.h" diff --git a/source/blender/imbuf/intern/thumbs_blend.c b/source/blender/imbuf/intern/thumbs_blend.c index 1d0964ebb62..486db07597f 100644 --- a/source/blender/imbuf/intern/thumbs_blend.c +++ b/source/blender/imbuf/intern/thumbs_blend.c @@ -68,7 +68,7 @@ ImBuf *IMB_thumb_load_blend(const char *blen_path, const char *blen_group, const printf("%s: error, found %d items, %d previews\n", __func__, nnames, nprevs); } BLI_linklist_free(previews, BKE_previewimg_freefunc); - BLI_linklist_free(names, free); + BLI_linklist_freeN(names); return ima; } @@ -78,22 +78,14 @@ ImBuf *IMB_thumb_load_blend(const char *blen_path, const char *blen_group, const if (STREQ(blockname, blen_id)) { if (img) { - unsigned int w = img->w[ICON_SIZE_PREVIEW]; - unsigned int h = img->h[ICON_SIZE_PREVIEW]; - unsigned int *rect = img->rect[ICON_SIZE_PREVIEW]; - - if (w > 0 && h > 0 && rect) { - /* first allocate imbuf for copying preview into it */ - ima = IMB_allocImBuf(w, h, 32, IB_rect); - memcpy(ima->rect, rect, w * h * sizeof(unsigned int)); - } + ima = BKE_previewimg_to_imbuf(img, ICON_SIZE_PREVIEW); } break; } } BLI_linklist_free(previews, BKE_previewimg_freefunc); - BLI_linklist_free(names, free); + BLI_linklist_freeN(names); } else { BlendThumbnail *data; diff --git a/source/blender/io/alembic/exporter/abc_hierarchy_iterator.h b/source/blender/io/alembic/exporter/abc_hierarchy_iterator.h index a0d9257b822..2098b8b2505 100644 --- a/source/blender/io/alembic/exporter/abc_hierarchy_iterator.h +++ b/source/blender/io/alembic/exporter/abc_hierarchy_iterator.h @@ -29,7 +29,6 @@ #include <Alembic/Abc/OObject.h> struct Depsgraph; -struct ID; struct Object; namespace blender::io::alembic { diff --git a/source/blender/io/alembic/exporter/abc_writer_abstract.h b/source/blender/io/alembic/exporter/abc_writer_abstract.h index d23e69cf73e..4997e498199 100644 --- a/source/blender/io/alembic/exporter/abc_writer_abstract.h +++ b/source/blender/io/alembic/exporter/abc_writer_abstract.h @@ -29,7 +29,6 @@ #include "DNA_material_types.h" struct IDProperty; -struct Material; struct Object; namespace blender::io::alembic { diff --git a/source/blender/io/alembic/exporter/abc_writer_hair.cc b/source/blender/io/alembic/exporter/abc_writer_hair.cc index f8d610a3659..80f2cadd08c 100644 --- a/source/blender/io/alembic/exporter/abc_writer_hair.cc +++ b/source/blender/io/alembic/exporter/abc_writer_hair.cc @@ -30,6 +30,7 @@ #include "BLI_math_geom.h" +#include "BKE_customdata.h" #include "BKE_mesh.h" #include "BKE_mesh_runtime.h" #include "BKE_particle.h" diff --git a/source/blender/io/alembic/exporter/abc_writer_hair.h b/source/blender/io/alembic/exporter/abc_writer_hair.h index 3759ffa4310..901fd70601f 100644 --- a/source/blender/io/alembic/exporter/abc_writer_hair.h +++ b/source/blender/io/alembic/exporter/abc_writer_hair.h @@ -23,9 +23,6 @@ #include <Alembic/AbcGeom/OCurves.h> #include <vector> -struct ParticleSettings; -struct ParticleSystem; - namespace blender::io::alembic { class ABCHairWriter : public ABCAbstractWriter { diff --git a/source/blender/io/alembic/intern/abc_reader_archive.h b/source/blender/io/alembic/intern/abc_reader_archive.h index 2a4fd6bd8fb..67000194aa1 100644 --- a/source/blender/io/alembic/intern/abc_reader_archive.h +++ b/source/blender/io/alembic/intern/abc_reader_archive.h @@ -28,7 +28,6 @@ #include <fstream> struct Main; -struct Scene; namespace blender::io::alembic { diff --git a/source/blender/io/alembic/intern/alembic_capi.cc b/source/blender/io/alembic/intern/alembic_capi.cc index c9eefbf9039..ad5a258f80c 100644 --- a/source/blender/io/alembic/intern/alembic_capi.cc +++ b/source/blender/io/alembic/intern/alembic_capi.cc @@ -35,6 +35,7 @@ #include "MEM_guardedalloc.h" #include "DNA_cachefile_types.h" +#include "DNA_collection_types.h" #include "DNA_curve_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" diff --git a/source/blender/io/collada/AnimationImporter.cpp b/source/blender/io/collada/AnimationImporter.cpp index 77ccdeae28d..9f54bf2aa28 100644 --- a/source/blender/io/collada/AnimationImporter.cpp +++ b/source/blender/io/collada/AnimationImporter.cpp @@ -385,7 +385,10 @@ virtual void AnimationImporter::change_eul_to_quat(Object *ob, bAction *act) char joint_path[100]; char rna_path[100]; - BLI_snprintf(joint_path, sizeof(joint_path), "pose.bones[\"%s\"]", grp->name); + char grp_name_esc[sizeof(grp->name) * 2]; + BLI_str_escape(grp_name_esc, grp->name, sizeof(grp_name_esc)); + + BLI_snprintf(joint_path, sizeof(joint_path), "pose.bones[\"%s\"]", grp_name_esc); BLI_snprintf(rna_path, sizeof(rna_path), "%s.rotation_quaternion", joint_path); FCurve *quatcu[4] = { diff --git a/source/blender/io/collada/ArmatureImporter.cpp b/source/blender/io/collada/ArmatureImporter.cpp index 9533ca322f9..7eef5c3f5fb 100644 --- a/source/blender/io/collada/ArmatureImporter.cpp +++ b/source/blender/io/collada/ArmatureImporter.cpp @@ -1037,7 +1037,9 @@ void ArmatureImporter::get_rna_path_for_joint(COLLADAFW::Node *node, char *joint_path, size_t count) { - BLI_snprintf(joint_path, count, "pose.bones[\"%s\"]", bc_get_joint_name(node)); + char bone_name_esc[sizeof(((Bone *)nullptr)->name) * 2]; + BLI_str_escape(bone_name_esc, bc_get_joint_name(node), sizeof(bone_name_esc)); + BLI_snprintf(joint_path, count, "pose.bones[\"%s\"]", bone_name_esc); } /* gives a world-space mat */ diff --git a/source/blender/io/collada/BCAnimationCurve.cpp b/source/blender/io/collada/BCAnimationCurve.cpp index 33eaf3376cd..5065accf554 100644 --- a/source/blender/io/collada/BCAnimationCurve.cpp +++ b/source/blender/io/collada/BCAnimationCurve.cpp @@ -173,8 +173,14 @@ std::string BCAnimationCurve::get_animation_name(Object *ob) const name = ""; } else { - const char *boneName = BLI_str_quoted_substrN(fcurve->rna_path, "pose.bones["); - name = (boneName) ? id_name(ob) + "_" + std::string(boneName) : ""; + char *boneName = BLI_str_quoted_substrN(fcurve->rna_path, "pose.bones["); + if (boneName) { + name = id_name(ob) + "_" + std::string(boneName); + MEM_freeN(boneName); + } + else { + name = ""; + } } } break; diff --git a/source/blender/io/collada/BCAnimationSampler.cpp b/source/blender/io/collada/BCAnimationSampler.cpp index abc770ceef5..a6ee0b8bee6 100644 --- a/source/blender/io/collada/BCAnimationSampler.cpp +++ b/source/blender/io/collada/BCAnimationSampler.cpp @@ -448,6 +448,7 @@ void BCAnimationSampler::initialize_curves(BCAnimationCurveMap &curves, Object * char *boneName = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones["); if (boneName) { object_type = BC_ANIMATION_TYPE_BONE; + MEM_freeN(boneName); } } diff --git a/source/blender/io/collada/collada_internal.cpp b/source/blender/io/collada/collada_internal.cpp index ed5cc62d05f..787af933e8f 100644 --- a/source/blender/io/collada/collada_internal.cpp +++ b/source/blender/io/collada/collada_internal.cpp @@ -205,7 +205,7 @@ const unsigned char translate_name_map[256] = { 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, }; -typedef std::map<std::string, std::vector<std::string>> map_string_list; +using map_string_list = std::map<std::string, std::vector<std::string>>; map_string_list global_id_map; void clear_global_id_map() diff --git a/source/blender/io/collada/collada_utils.cpp b/source/blender/io/collada/collada_utils.cpp index ab08084db4b..ceeffe070df 100644 --- a/source/blender/io/collada/collada_utils.cpp +++ b/source/blender/io/collada/collada_utils.cpp @@ -832,7 +832,9 @@ void bc_enable_fcurves(bAction *act, char *bone_name) char prefix[200]; if (bone_name) { - BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone_name); + char bone_name_esc[sizeof(((Bone *)nullptr)->name) * 2]; + BLI_str_escape(bone_name_esc, bone_name, sizeof(bone_name_esc)); + BLI_snprintf(prefix, sizeof(prefix), "pose.bones[\"%s\"]", bone_name_esc); } for (fcu = (FCurve *)act->curves.first; fcu; fcu = fcu->next) { @@ -1176,17 +1178,6 @@ static std::string bc_get_uvlayer_name(Mesh *me, int layer) return ""; } -std::string bc_find_bonename_in_path(std::string path, std::string probe) -{ - std::string result; - char *boneName = BLI_str_quoted_substrN(path.c_str(), probe.c_str()); - if (boneName) { - result = std::string(boneName); - MEM_freeN(boneName); - } - return result; -} - static bNodeTree *prepare_material_nodetree(Material *ma) { if (ma->nodetree == nullptr) { diff --git a/source/blender/io/collada/collada_utils.h b/source/blender/io/collada/collada_utils.h index fa65d398954..d0a5d37d6d2 100644 --- a/source/blender/io/collada/collada_utils.h +++ b/source/blender/io/collada/collada_utils.h @@ -146,8 +146,6 @@ extern void bc_bubble_sort_by_Object_name(LinkNode *export_set); extern bool bc_is_root_bone(Bone *aBone, bool deform_bones_only); extern int bc_get_active_UVLayer(Object *ob); -std::string bc_find_bonename_in_path(std::string path, std::string probe); - inline std::string bc_string_after(const std::string &s, const std::string probe) { size_t i = s.rfind(probe); diff --git a/source/blender/io/common/IO_abstract_hierarchy_iterator.h b/source/blender/io/common/IO_abstract_hierarchy_iterator.h index e066ca8ba8f..300c555ac8f 100644 --- a/source/blender/io/common/IO_abstract_hierarchy_iterator.h +++ b/source/blender/io/common/IO_abstract_hierarchy_iterator.h @@ -43,13 +43,11 @@ #include <set> #include <string> -struct Base; struct Depsgraph; struct DupliObject; struct ID; struct Object; struct ParticleSystem; -struct ViewLayer; namespace blender::io { diff --git a/source/blender/io/common/intern/abstract_hierarchy_iterator_test.cc b/source/blender/io/common/intern/abstract_hierarchy_iterator_test.cc index 8acdba416d3..457d68953ff 100644 --- a/source/blender/io/common/intern/abstract_hierarchy_iterator_test.cc +++ b/source/blender/io/common/intern/abstract_hierarchy_iterator_test.cc @@ -36,7 +36,7 @@ namespace { /* Mapping from ID.name to set of export hierarchy path. Duplicated objects can be exported * multiple times with different export paths, hence the set. */ -typedef std::map<std::string, std::set<std::string>> used_writers; +using used_writers = std::map<std::string, std::set<std::string>>; class TestHierarchyWriter : public AbstractHierarchyWriter { public: diff --git a/source/blender/io/usd/intern/usd_exporter_context.h b/source/blender/io/usd/intern/usd_exporter_context.h index 41ff34b327e..66e87f0eed1 100644 --- a/source/blender/io/usd/intern/usd_exporter_context.h +++ b/source/blender/io/usd/intern/usd_exporter_context.h @@ -24,7 +24,6 @@ #include <pxr/usd/usd/common.h> struct Depsgraph; -struct Object; namespace blender::io::usd { diff --git a/source/blender/io/usd/intern/usd_hierarchy_iterator.h b/source/blender/io/usd/intern/usd_hierarchy_iterator.h index 922ab761bd9..cd19becbb07 100644 --- a/source/blender/io/usd/intern/usd_hierarchy_iterator.h +++ b/source/blender/io/usd/intern/usd_hierarchy_iterator.h @@ -28,7 +28,6 @@ #include <pxr/usd/usd/timeCode.h> struct Depsgraph; -struct ID; struct Object; namespace blender::io::usd { diff --git a/source/blender/io/usd/intern/usd_writer_abstract.h b/source/blender/io/usd/intern/usd_writer_abstract.h index 6a3b8d515dc..2143164e3dd 100644 --- a/source/blender/io/usd/intern/usd_writer_abstract.h +++ b/source/blender/io/usd/intern/usd_writer_abstract.h @@ -33,7 +33,6 @@ #include "DNA_material_types.h" struct Material; -struct Object; namespace blender::io::usd { diff --git a/source/blender/io/usd/usd.h b/source/blender/io/usd/usd.h index b9ea90736ff..40e2d0d8674 100644 --- a/source/blender/io/usd/usd.h +++ b/source/blender/io/usd/usd.h @@ -25,7 +25,6 @@ extern "C" { #endif -struct Scene; struct bContext; struct USDExportParams { diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index f2d860a2851..265baa16cc5 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -264,7 +264,12 @@ typedef struct IDOverrideLibrary { typedef struct ID { void *next, *prev; struct ID *newid; + struct Library *lib; + + /** If the ID is an asset, this pointer is set. Owning pointer. */ + struct AssetMetaData *asset_data; + /** MAX_ID_NAME. */ char name[66]; /** @@ -310,6 +315,7 @@ typedef struct ID { struct ID *orig_id; void *py_instance; + void *_pad1; } ID; /** @@ -354,6 +360,7 @@ enum eIconSizes { enum ePreviewImage_Flag { PRV_CHANGED = (1 << 0), PRV_USER_EDITED = (1 << 1), /* if user-edited, do not auto-update this anymore! */ + PRV_UNFINISHED = (1 << 2), /* The preview is not done rendering yet. */ }; /* for PreviewImage->tag */ @@ -502,6 +509,8 @@ typedef enum ID_Type { #define ID_IS_OVERRIDE_LIBRARY_TEMPLATE(_id) \ (((ID *)(_id))->override_library != NULL && ((ID *)(_id))->override_library->reference == NULL) +#define ID_IS_ASSET(_id) (((const ID *)(_id))->asset_data != NULL) + /* Check whether datablock type is covered by copy-on-write. */ #define ID_TYPE_IS_COW(_id_type) (!ELEM(_id_type, ID_BR, ID_PAL, ID_IM)) diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h index 9a31447dacd..1eafa655195 100644 --- a/source/blender/makesdna/DNA_anim_types.h +++ b/source/blender/makesdna/DNA_anim_types.h @@ -612,9 +612,18 @@ typedef struct FCurve { char _pad[3]; /* RNA - data link */ - /** If applicable, the index of the RNA-array item to get. */ + /** + * When the RNA property from `rna_path` is an array, use this to access the array index. + * + * \note This may be negative (as it wasn't prevented in 2.91 and older). + * Currently it silently fails to resolve the data-path in this case. + */ int array_index; - /** RNA-path to resolve data-access. */ + /** + * RNA-path to resolve data-access, see: #RNA_path_resolve_property. + * + * \note String look-ups for collection and custom-properties are escaped using #BLI_str_escape. + */ char *rna_path; /* curve coloring (for editor) */ @@ -875,6 +884,10 @@ typedef enum eNlaTrack_Flag { /** track is not allowed to execute, * usually as result of tweaking being enabled (internal flag) */ NLATRACK_DISABLED = (1 << 10), + + /** This NLA track is added to an override ID, which means it is fully editable. + * Irrelevant in case the owner ID is not an override. */ + NLATRACK_OVERRIDELIBRARY_LOCAL = 1 << 16, } eNlaTrack_Flag; /* ************************************ */ diff --git a/source/blender/makesdna/DNA_asset_defaults.h b/source/blender/makesdna/DNA_asset_defaults.h new file mode 100644 index 00000000000..ff00ba79cf0 --- /dev/null +++ b/source/blender/makesdna/DNA_asset_defaults.h @@ -0,0 +1,37 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup DNA + */ + +#pragma once + +/* Struct members on own line. */ +/* clang-format off */ + +/* -------------------------------------------------------------------- */ +/** \name Asset Struct + * \{ */ + +#define _DNA_DEFAULT_AssetMetaData \ + { \ + 0 \ + } + +/** \} */ + +/* clang-format on */ diff --git a/source/blender/makesdna/DNA_asset_types.h b/source/blender/makesdna/DNA_asset_types.h new file mode 100644 index 00000000000..671012e54ef --- /dev/null +++ b/source/blender/makesdna/DNA_asset_types.h @@ -0,0 +1,62 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup DNA + */ + +#ifndef __DNA_ASSET_TYPES_H__ +#define __DNA_ASSET_TYPES_H__ + +#include "DNA_listBase.h" + +/** + * \brief User defined tag. + * Currently only used by assets, could be used more often at some point. + * Maybe add a custom icon and color to these in future? + */ +typedef struct AssetTag { + struct AssetTag *next, *prev; + char name[64]; /* MAX_NAME */ +} AssetTag; + +/** + * \brief The meta-data of an asset. + * By creating and giving this for a data-block (#ID.asset_data), the data-block becomes an asset. + * + * \note This struct must be readable without having to read anything but blocks from the ID it is + * attached to! That way, asset information of a file can be read, without reading anything + * more than that from the file. So pointers to other IDs or ID data are strictly forbidden. + */ +typedef struct AssetMetaData { + /** Custom asset meta-data. Cannot store pointers to IDs (#STRUCT_NO_DATABLOCK_IDPROPERTIES)! */ + struct IDProperty *properties; + + /** Optional description of this asset for display in the UI. Dynamic length. */ + char *description; + /** User defined tags for this asset. The asset manager uses these for filtering, but how they + * function exactly (e.g. how they are registered to provide a list of searchable available tags) + * is up to the asset-engine. */ + ListBase tags; /* AssetTag */ + short active_tag; + /** Store the number of tags to avoid continuous counting. Could be turned into runtime data, we + * can always reliably reconstruct it from the list. */ + short tot_tags; + + char _pad[4]; +} AssetMetaData; + +#endif /* __DNA_ASSET_TYPES_H__ */ diff --git a/source/blender/makesdna/DNA_brush_enums.h b/source/blender/makesdna/DNA_brush_enums.h new file mode 100644 index 00000000000..79e3b313bf1 --- /dev/null +++ b/source/blender/makesdna/DNA_brush_enums.h @@ -0,0 +1,619 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup DNA + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/* BrushGpencilSettings->preset_type. + * Use a range for each group and not continuous values.*/ +typedef enum eGPBrush_Presets { + GP_BRUSH_PRESET_UNKNOWN = 0, + + /* Draw 1-99. */ + GP_BRUSH_PRESET_AIRBRUSH = 1, + GP_BRUSH_PRESET_INK_PEN = 2, + GP_BRUSH_PRESET_INK_PEN_ROUGH = 3, + GP_BRUSH_PRESET_MARKER_BOLD = 4, + GP_BRUSH_PRESET_MARKER_CHISEL = 5, + GP_BRUSH_PRESET_PEN = 6, + GP_BRUSH_PRESET_PENCIL_SOFT = 7, + GP_BRUSH_PRESET_PENCIL = 8, + GP_BRUSH_PRESET_FILL_AREA = 9, + GP_BRUSH_PRESET_ERASER_SOFT = 10, + GP_BRUSH_PRESET_ERASER_HARD = 11, + GP_BRUSH_PRESET_ERASER_POINT = 12, + GP_BRUSH_PRESET_ERASER_STROKE = 13, + GP_BRUSH_PRESET_TINT = 14, + + /* Vertex Paint 100-199. */ + GP_BRUSH_PRESET_VERTEX_DRAW = 100, + GP_BRUSH_PRESET_VERTEX_BLUR = 101, + GP_BRUSH_PRESET_VERTEX_AVERAGE = 102, + GP_BRUSH_PRESET_VERTEX_SMEAR = 103, + GP_BRUSH_PRESET_VERTEX_REPLACE = 104, + + /* Sculpt 200-299. */ + GP_BRUSH_PRESET_SMOOTH_STROKE = 200, + GP_BRUSH_PRESET_STRENGTH_STROKE = 201, + GP_BRUSH_PRESET_THICKNESS_STROKE = 202, + GP_BRUSH_PRESET_GRAB_STROKE = 203, + GP_BRUSH_PRESET_PUSH_STROKE = 204, + GP_BRUSH_PRESET_TWIST_STROKE = 205, + GP_BRUSH_PRESET_PINCH_STROKE = 206, + GP_BRUSH_PRESET_RANDOMIZE_STROKE = 207, + GP_BRUSH_PRESET_CLONE_STROKE = 208, + + /* Weight Paint 300-399. */ + GP_BRUSH_PRESET_DRAW_WEIGHT = 300, +} eGPBrush_Presets; + +/* BrushGpencilSettings->flag */ +typedef enum eGPDbrush_Flag { + /* brush use pressure */ + GP_BRUSH_USE_PRESSURE = (1 << 0), + /* brush use pressure for alpha factor */ + GP_BRUSH_USE_STRENGTH_PRESSURE = (1 << 1), + /* brush use pressure for alpha factor */ + GP_BRUSH_USE_JITTER_PRESSURE = (1 << 2), + /* fill hide transparent */ + GP_BRUSH_FILL_HIDE = (1 << 6), + /* show fill help lines */ + GP_BRUSH_FILL_SHOW_HELPLINES = (1 << 7), + /* lazy mouse */ + GP_BRUSH_STABILIZE_MOUSE = (1 << 8), + /* lazy mouse override (internal only) */ + GP_BRUSH_STABILIZE_MOUSE_TEMP = (1 << 9), + /* default eraser brush for quick switch */ + GP_BRUSH_DEFAULT_ERASER = (1 << 10), + /* settings group */ + GP_BRUSH_GROUP_SETTINGS = (1 << 11), + /* Random settings group */ + GP_BRUSH_GROUP_RANDOM = (1 << 12), + /* Keep material assigned to brush */ + GP_BRUSH_MATERIAL_PINNED = (1 << 13), + /* Do not show fill color while drawing (no lasso mode) */ + GP_BRUSH_DISSABLE_LASSO = (1 << 14), + /* Do not erase strokes oLcluded */ + GP_BRUSH_OCCLUDE_ERASER = (1 << 15), + /* Post process trim stroke */ + GP_BRUSH_TRIM_STROKE = (1 << 16), +} eGPDbrush_Flag; + +typedef enum eGPDbrush_Flag2 { + /* Brush use random Hue at stroke level */ + GP_BRUSH_USE_HUE_AT_STROKE = (1 << 0), + /* Brush use random Saturation at stroke level */ + GP_BRUSH_USE_SAT_AT_STROKE = (1 << 1), + /* Brush use random Value at stroke level */ + GP_BRUSH_USE_VAL_AT_STROKE = (1 << 2), + /* Brush use random Pressure at stroke level */ + GP_BRUSH_USE_PRESS_AT_STROKE = (1 << 3), + /* Brush use random Strength at stroke level */ + GP_BRUSH_USE_STRENGTH_AT_STROKE = (1 << 4), + /* Brush use random UV at stroke level */ + GP_BRUSH_USE_UV_AT_STROKE = (1 << 5), + /* Brush use Hue random pressure */ + GP_BRUSH_USE_HUE_RAND_PRESS = (1 << 6), + /* Brush use Saturation random pressure */ + GP_BRUSH_USE_SAT_RAND_PRESS = (1 << 7), + /* Brush use Value random pressure */ + GP_BRUSH_USE_VAL_RAND_PRESS = (1 << 8), + /* Brush use Pressure random pressure */ + GP_BRUSH_USE_PRESSURE_RAND_PRESS = (1 << 9), + /* Brush use Strength random pressure */ + GP_BRUSH_USE_STRENGTH_RAND_PRESS = (1 << 10), + /* Brush use UV random pressure */ + GP_BRUSH_USE_UV_RAND_PRESS = (1 << 11), +} eGPDbrush_Flag2; + +/* BrushGpencilSettings->gp_fill_draw_mode */ +typedef enum eGP_FillDrawModes { + GP_FILL_DMODE_BOTH = 0, + GP_FILL_DMODE_STROKE = 1, + GP_FILL_DMODE_CONTROL = 2, +} eGP_FillDrawModes; + +/* BrushGpencilSettings->fill_layer_mode */ +typedef enum eGP_FillLayerModes { + GP_FILL_GPLMODE_VISIBLE = 0, + GP_FILL_GPLMODE_ACTIVE = 1, + GP_FILL_GPLMODE_ALL_ABOVE = 2, + GP_FILL_GPLMODE_ALL_BELOW = 3, + GP_FILL_GPLMODE_ABOVE = 4, + GP_FILL_GPLMODE_BELOW = 5, +} eGP_FillLayerModes; + +/* BrushGpencilSettings->gp_eraser_mode */ +typedef enum eGP_BrushEraserMode { + GP_BRUSH_ERASER_SOFT = 0, + GP_BRUSH_ERASER_HARD = 1, + GP_BRUSH_ERASER_STROKE = 2, +} eGP_BrushEraserMode; + +/* BrushGpencilSettings->brush_draw_mode */ +typedef enum eGP_BrushMode { + GP_BRUSH_MODE_ACTIVE = 0, + GP_BRUSH_MODE_MATERIAL = 1, + GP_BRUSH_MODE_VERTEXCOLOR = 2, +} eGP_BrushMode; + +/* BrushGpencilSettings default brush icons */ +typedef enum eGP_BrushIcons { + GP_BRUSH_ICON_PENCIL = 1, + GP_BRUSH_ICON_PEN = 2, + GP_BRUSH_ICON_INK = 3, + GP_BRUSH_ICON_INKNOISE = 4, + GP_BRUSH_ICON_BLOCK = 5, + GP_BRUSH_ICON_MARKER = 6, + GP_BRUSH_ICON_FILL = 7, + GP_BRUSH_ICON_ERASE_SOFT = 8, + GP_BRUSH_ICON_ERASE_HARD = 9, + GP_BRUSH_ICON_ERASE_STROKE = 10, + GP_BRUSH_ICON_AIRBRUSH = 11, + GP_BRUSH_ICON_CHISEL = 12, + GP_BRUSH_ICON_TINT = 13, + GP_BRUSH_ICON_VERTEX_DRAW = 14, + GP_BRUSH_ICON_VERTEX_BLUR = 15, + GP_BRUSH_ICON_VERTEX_AVERAGE = 16, + GP_BRUSH_ICON_VERTEX_SMEAR = 17, + GP_BRUSH_ICON_VERTEX_REPLACE = 18, + GP_BRUSH_ICON_GPBRUSH_SMOOTH = 19, + GP_BRUSH_ICON_GPBRUSH_THICKNESS = 20, + GP_BRUSH_ICON_GPBRUSH_STRENGTH = 21, + GP_BRUSH_ICON_GPBRUSH_RANDOMIZE = 22, + GP_BRUSH_ICON_GPBRUSH_GRAB = 23, + GP_BRUSH_ICON_GPBRUSH_PUSH = 24, + GP_BRUSH_ICON_GPBRUSH_TWIST = 25, + GP_BRUSH_ICON_GPBRUSH_PINCH = 26, + GP_BRUSH_ICON_GPBRUSH_CLONE = 27, + GP_BRUSH_ICON_GPBRUSH_WEIGHT = 28, +} eGP_BrushIcons; + +typedef enum eBrushCurvePreset { + BRUSH_CURVE_CUSTOM = 0, + BRUSH_CURVE_SMOOTH = 1, + BRUSH_CURVE_SPHERE = 2, + BRUSH_CURVE_ROOT = 3, + BRUSH_CURVE_SHARP = 4, + BRUSH_CURVE_LIN = 5, + BRUSH_CURVE_POW4 = 6, + BRUSH_CURVE_INVSQUARE = 7, + BRUSH_CURVE_CONSTANT = 8, + BRUSH_CURVE_SMOOTHER = 9, +} eBrushCurvePreset; + +typedef enum eBrushDeformTarget { + BRUSH_DEFORM_TARGET_GEOMETRY = 0, + BRUSH_DEFORM_TARGET_CLOTH_SIM = 1, +} eBrushDeformTarget; + +typedef enum eBrushElasticDeformType { + BRUSH_ELASTIC_DEFORM_GRAB = 0, + BRUSH_ELASTIC_DEFORM_GRAB_BISCALE = 1, + BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE = 2, + BRUSH_ELASTIC_DEFORM_SCALE = 3, + BRUSH_ELASTIC_DEFORM_TWIST = 4, +} eBrushElasticDeformType; + +typedef enum eBrushClothDeformType { + BRUSH_CLOTH_DEFORM_DRAG = 0, + BRUSH_CLOTH_DEFORM_PUSH = 1, + BRUSH_CLOTH_DEFORM_GRAB = 2, + BRUSH_CLOTH_DEFORM_PINCH_POINT = 3, + BRUSH_CLOTH_DEFORM_PINCH_PERPENDICULAR = 4, + BRUSH_CLOTH_DEFORM_INFLATE = 5, + BRUSH_CLOTH_DEFORM_EXPAND = 6, + BRUSH_CLOTH_DEFORM_SNAKE_HOOK = 7, +} eBrushClothDeformType; + +typedef enum eBrushSmoothDeformType { + BRUSH_SMOOTH_DEFORM_LAPLACIAN = 0, + BRUSH_SMOOTH_DEFORM_SURFACE = 1, +} eBrushSmoothDeformType; + +typedef enum eBrushClothForceFalloffType { + BRUSH_CLOTH_FORCE_FALLOFF_RADIAL = 0, + BRUSH_CLOTH_FORCE_FALLOFF_PLANE = 1, +} eBrushClothForceFalloffType; + +typedef enum eBrushClothSimulationAreaType { + BRUSH_CLOTH_SIMULATION_AREA_LOCAL = 0, + BRUSH_CLOTH_SIMULATION_AREA_GLOBAL = 1, + BRUSH_CLOTH_SIMULATION_AREA_DYNAMIC = 2, +} eBrushClothSimulationAreaType; + +typedef enum eBrushPoseDeformType { + BRUSH_POSE_DEFORM_ROTATE_TWIST = 0, + BRUSH_POSE_DEFORM_SCALE_TRASLATE = 1, + BRUSH_POSE_DEFORM_SQUASH_STRETCH = 2, +} eBrushPoseDeformType; + +typedef enum eBrushPoseOriginType { + BRUSH_POSE_ORIGIN_TOPOLOGY = 0, + BRUSH_POSE_ORIGIN_FACE_SETS = 1, + BRUSH_POSE_ORIGIN_FACE_SETS_FK = 2, +} eBrushPoseOriginType; + +typedef enum eBrushSmearDeformType { + BRUSH_SMEAR_DEFORM_DRAG = 0, + BRUSH_SMEAR_DEFORM_PINCH = 1, + BRUSH_SMEAR_DEFORM_EXPAND = 2, +} eBrushSmearDeformType; + +typedef enum eBrushSlideDeformType { + BRUSH_SLIDE_DEFORM_DRAG = 0, + BRUSH_SLIDE_DEFORM_PINCH = 1, + BRUSH_SLIDE_DEFORM_EXPAND = 2, +} eBrushSlideDeformType; + +typedef enum eBrushBoundaryDeformType { + BRUSH_BOUNDARY_DEFORM_BEND = 0, + BRUSH_BOUNDARY_DEFORM_EXPAND = 1, + BRUSH_BOUNDARY_DEFORM_INFLATE = 2, + BRUSH_BOUNDARY_DEFORM_GRAB = 3, + BRUSH_BOUNDARY_DEFORM_TWIST = 4, + BRUSH_BOUNDARY_DEFORM_SMOOTH = 5, +} eBrushBushBoundaryDeformType; + +typedef enum eBrushBoundaryFalloffType { + BRUSH_BOUNDARY_FALLOFF_CONSTANT = 0, + BRUSH_BOUNDARY_FALLOFF_RADIUS = 1, + BRUSH_BOUNDARY_FALLOFF_LOOP = 2, + BRUSH_BOUNDARY_FALLOFF_LOOP_INVERT = 3, +} eBrushBoundaryFalloffType; + +typedef enum eBrushSnakeHookDeformType { + BRUSH_SNAKE_HOOK_DEFORM_FALLOFF = 0, + BRUSH_SNAKE_HOOK_DEFORM_ELASTIC = 1, +} eBrushSnakeHookDeformType; + +/* Gpencilsettings.Vertex_mode */ +typedef enum eGp_Vertex_Mode { + /* Affect to Stroke only. */ + GPPAINT_MODE_STROKE = 0, + /* Affect to Fill only. */ + GPPAINT_MODE_FILL = 1, + /* Affect to both. */ + GPPAINT_MODE_BOTH = 2, +} eGp_Vertex_Mode; + +/* sculpt_flag */ +typedef enum eGP_Sculpt_Flag { + /* invert the effect of the brush */ + GP_SCULPT_FLAG_INVERT = (1 << 0), + /* smooth brush affects pressure values as well */ + GP_SCULPT_FLAG_SMOOTH_PRESSURE = (1 << 2), + /* temporary invert action */ + GP_SCULPT_FLAG_TMP_INVERT = (1 << 3), +} eGP_Sculpt_Flag; + +/* sculpt_mode_flag */ +typedef enum eGP_Sculpt_Mode_Flag { + /* apply brush to position */ + GP_SCULPT_FLAGMODE_APPLY_POSITION = (1 << 0), + /* apply brush to strength */ + GP_SCULPT_FLAGMODE_APPLY_STRENGTH = (1 << 1), + /* apply brush to thickness */ + GP_SCULPT_FLAGMODE_APPLY_THICKNESS = (1 << 2), + /* apply brush to uv data */ + GP_SCULPT_FLAGMODE_APPLY_UV = (1 << 3), +} eGP_Sculpt_Mode_Flag; + +typedef enum eAutomasking_flag { + BRUSH_AUTOMASKING_TOPOLOGY = (1 << 0), + BRUSH_AUTOMASKING_FACE_SETS = (1 << 1), + BRUSH_AUTOMASKING_BOUNDARY_EDGES = (1 << 2), + BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS = (1 << 3), +} eAutomasking_flag; + +typedef enum ePaintBrush_flag { + BRUSH_PAINT_HARDNESS_PRESSURE = (1 << 0), + BRUSH_PAINT_HARDNESS_PRESSURE_INVERT = (1 << 1), + BRUSH_PAINT_FLOW_PRESSURE = (1 << 2), + BRUSH_PAINT_FLOW_PRESSURE_INVERT = (1 << 3), + BRUSH_PAINT_WET_MIX_PRESSURE = (1 << 4), + BRUSH_PAINT_WET_MIX_PRESSURE_INVERT = (1 << 5), + BRUSH_PAINT_WET_PERSISTENCE_PRESSURE = (1 << 6), + BRUSH_PAINT_WET_PERSISTENCE_PRESSURE_INVERT = (1 << 7), + BRUSH_PAINT_DENSITY_PRESSURE = (1 << 8), + BRUSH_PAINT_DENSITY_PRESSURE_INVERT = (1 << 9), +} ePaintBrush_flag; + +/* Brush.gradient_source */ +typedef enum eBrushGradientSourceStroke { + BRUSH_GRADIENT_PRESSURE = 0, /* gradient from pressure */ + BRUSH_GRADIENT_SPACING_REPEAT = 1, /* gradient from spacing */ + BRUSH_GRADIENT_SPACING_CLAMP = 2, /* gradient from spacing */ +} eBrushGradientSourceStroke; + +typedef enum eBrushGradientSourceFill { + BRUSH_GRADIENT_LINEAR = 0, /* gradient from pressure */ + BRUSH_GRADIENT_RADIAL = 1, /* gradient from spacing */ +} eBrushGradientSourceFill; + +/* Brush.flag */ +typedef enum eBrushFlags { + BRUSH_AIRBRUSH = (1 << 0), + BRUSH_INVERT_TO_SCRAPE_FILL = (1 << 1), + BRUSH_ALPHA_PRESSURE = (1 << 2), + BRUSH_SIZE_PRESSURE = (1 << 3), + BRUSH_JITTER_PRESSURE = (1 << 4), + BRUSH_SPACING_PRESSURE = (1 << 5), + BRUSH_ORIGINAL_PLANE = (1 << 6), + BRUSH_GRAB_ACTIVE_VERTEX = (1 << 7), + BRUSH_ANCHORED = (1 << 8), + BRUSH_DIR_IN = (1 << 9), + BRUSH_SPACE = (1 << 10), + BRUSH_SMOOTH_STROKE = (1 << 11), + BRUSH_PERSISTENT = (1 << 12), + BRUSH_ACCUMULATE = (1 << 13), + BRUSH_LOCK_ALPHA = (1 << 14), + BRUSH_ORIGINAL_NORMAL = (1 << 15), + BRUSH_OFFSET_PRESSURE = (1 << 16), + BRUSH_SCENE_SPACING = (1 << 17), + BRUSH_SPACE_ATTEN = (1 << 18), + BRUSH_ADAPTIVE_SPACE = (1 << 19), + BRUSH_LOCK_SIZE = (1 << 20), + BRUSH_USE_GRADIENT = (1 << 21), + BRUSH_EDGE_TO_EDGE = (1 << 22), + BRUSH_DRAG_DOT = (1 << 23), + BRUSH_INVERSE_SMOOTH_PRESSURE = (1 << 24), + BRUSH_FRONTFACE_FALLOFF = (1 << 25), + BRUSH_PLANE_TRIM = (1 << 26), + BRUSH_FRONTFACE = (1 << 27), + BRUSH_CUSTOM_ICON = (1 << 28), + BRUSH_LINE = (1 << 29), + BRUSH_ABSOLUTE_JITTER = (1 << 30), + BRUSH_CURVE = (1u << 31), +} eBrushFlags; + +/* Brush.sampling_flag */ +typedef enum eBrushSamplingFlags { + BRUSH_PAINT_ANTIALIASING = (1 << 0), +} eBrushSamplingFlags; + +/* Brush.flag2 */ +typedef enum eBrushFlags2 { + BRUSH_MULTIPLANE_SCRAPE_DYNAMIC = (1 << 0), + BRUSH_MULTIPLANE_SCRAPE_PLANES_PREVIEW = (1 << 1), + BRUSH_POSE_IK_ANCHORED = (1 << 2), + BRUSH_USE_CONNECTED_ONLY = (1 << 3), + BRUSH_CLOTH_PIN_SIMULATION_BOUNDARY = (1 << 4), + BRUSH_POSE_USE_LOCK_ROTATION = (1 << 5), + BRUSH_CLOTH_USE_COLLISION = (1 << 6), + BRUSH_AREA_RADIUS_PRESSURE = (1 << 7), + BRUSH_GRAB_SILHOUETTE = (1 << 8), +} eBrushFlags2; + +typedef enum { + BRUSH_MASK_PRESSURE_RAMP = (1 << 1), + BRUSH_MASK_PRESSURE_CUTOFF = (1 << 2), +} BrushMaskPressureFlags; + +/* Brush.overlay_flags */ +typedef enum eOverlayFlags { + BRUSH_OVERLAY_CURSOR = (1), + BRUSH_OVERLAY_PRIMARY = (1 << 1), + BRUSH_OVERLAY_SECONDARY = (1 << 2), + BRUSH_OVERLAY_CURSOR_OVERRIDE_ON_STROKE = (1 << 3), + BRUSH_OVERLAY_PRIMARY_OVERRIDE_ON_STROKE = (1 << 4), + BRUSH_OVERLAY_SECONDARY_OVERRIDE_ON_STROKE = (1 << 5), +} eOverlayFlags; + +#define BRUSH_OVERLAY_OVERRIDE_MASK \ + (BRUSH_OVERLAY_CURSOR_OVERRIDE_ON_STROKE | BRUSH_OVERLAY_PRIMARY_OVERRIDE_ON_STROKE | \ + BRUSH_OVERLAY_SECONDARY_OVERRIDE_ON_STROKE) + +/* Brush.sculpt_tool */ +typedef enum eBrushSculptTool { + SCULPT_TOOL_DRAW = 1, + SCULPT_TOOL_SMOOTH = 2, + SCULPT_TOOL_PINCH = 3, + SCULPT_TOOL_INFLATE = 4, + SCULPT_TOOL_GRAB = 5, + SCULPT_TOOL_LAYER = 6, + SCULPT_TOOL_FLATTEN = 7, + SCULPT_TOOL_CLAY = 8, + SCULPT_TOOL_FILL = 9, + SCULPT_TOOL_SCRAPE = 10, + SCULPT_TOOL_NUDGE = 11, + SCULPT_TOOL_THUMB = 12, + SCULPT_TOOL_SNAKE_HOOK = 13, + SCULPT_TOOL_ROTATE = 14, + SCULPT_TOOL_SIMPLIFY = 15, + SCULPT_TOOL_CREASE = 16, + SCULPT_TOOL_BLOB = 17, + SCULPT_TOOL_CLAY_STRIPS = 18, + SCULPT_TOOL_MASK = 19, + SCULPT_TOOL_DRAW_SHARP = 20, + SCULPT_TOOL_ELASTIC_DEFORM = 21, + SCULPT_TOOL_POSE = 22, + SCULPT_TOOL_MULTIPLANE_SCRAPE = 23, + SCULPT_TOOL_SLIDE_RELAX = 24, + SCULPT_TOOL_CLAY_THUMB = 25, + SCULPT_TOOL_CLOTH = 26, + SCULPT_TOOL_DRAW_FACE_SETS = 27, + SCULPT_TOOL_PAINT = 28, + SCULPT_TOOL_SMEAR = 29, + SCULPT_TOOL_BOUNDARY = 30, + SCULPT_TOOL_DISPLACEMENT_ERASER = 31, + SCULPT_TOOL_DISPLACEMENT_SMEAR = 32, + SCULPT_TOOL_VCOL_BOUNDARY = 33, +} eBrushSculptTool; + +/* Brush.uv_sculpt_tool */ +typedef enum eBrushUVSculptTool { + UV_SCULPT_TOOL_GRAB = 0, + UV_SCULPT_TOOL_RELAX = 1, + UV_SCULPT_TOOL_PINCH = 2, +} eBrushUVSculptTool; + +#define SCULPT_TOOL_HAS_VCOL_BOUNDARY_SMOOTH(t) \ + ELEM(t, \ + SCULPT_TOOL_PAINT,\ + SCULPT_TOOL_SMEAR) + +/** When #BRUSH_ACCUMULATE is used */ +#define SCULPT_TOOL_HAS_ACCUMULATE(t) \ + ELEM(t, \ + SCULPT_TOOL_DRAW, \ + SCULPT_TOOL_DRAW_SHARP, \ + SCULPT_TOOL_SLIDE_RELAX, \ + SCULPT_TOOL_CREASE, \ + SCULPT_TOOL_BLOB, \ + SCULPT_TOOL_INFLATE, \ + SCULPT_TOOL_CLAY, \ + SCULPT_TOOL_CLAY_STRIPS, \ + SCULPT_TOOL_CLAY_THUMB, \ + SCULPT_TOOL_ROTATE, \ + SCULPT_TOOL_SCRAPE, \ + SCULPT_TOOL_FLATTEN) + +#define SCULPT_TOOL_HAS_NORMAL_WEIGHT(t) \ + ELEM(t, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_ELASTIC_DEFORM) + +#define SCULPT_TOOL_HAS_RAKE(t) ELEM(t, SCULPT_TOOL_SNAKE_HOOK) + +#define SCULPT_TOOL_HAS_DYNTOPO(t) \ + (ELEM(t, /* These brushes, as currently coded, cannot support dynamic topology */ \ + SCULPT_TOOL_GRAB, \ + SCULPT_TOOL_ROTATE, \ + SCULPT_TOOL_CLOTH, \ + SCULPT_TOOL_THUMB, \ + SCULPT_TOOL_LAYER, \ + SCULPT_TOOL_DISPLACEMENT_ERASER, \ + SCULPT_TOOL_SLIDE_RELAX, \ + SCULPT_TOOL_ELASTIC_DEFORM, \ + SCULPT_TOOL_BOUNDARY, \ + SCULPT_TOOL_POSE, \ + SCULPT_TOOL_DRAW_FACE_SETS, \ + SCULPT_TOOL_PAINT, \ + SCULPT_TOOL_SMEAR, \ +\ + /* These brushes could handle dynamic topology, \ \ + * but user feedback indicates it's better not to */ \ + SCULPT_TOOL_SMOOTH, \ + SCULPT_TOOL_MASK) == 0) + +#define SCULPT_TOOL_HAS_TOPOLOGY_RAKE(t) \ + (ELEM(t, /* These brushes, as currently coded, cannot support topology rake. */ \ + SCULPT_TOOL_GRAB, \ + SCULPT_TOOL_ROTATE, \ + SCULPT_TOOL_THUMB, \ + SCULPT_TOOL_DRAW_SHARP, \ + SCULPT_TOOL_DISPLACEMENT_ERASER, \ + SCULPT_TOOL_SLIDE_RELAX, \ + SCULPT_TOOL_MASK) == 0) + +/* ImagePaintSettings.tool */ +typedef enum eBrushImagePaintTool { + PAINT_TOOL_DRAW = 0, + PAINT_TOOL_SOFTEN = 1, + PAINT_TOOL_SMEAR = 2, + PAINT_TOOL_CLONE = 3, + PAINT_TOOL_FILL = 4, + PAINT_TOOL_MASK = 5, +} eBrushImagePaintTool; + +typedef enum eBrushVertexPaintTool { + VPAINT_TOOL_DRAW = 0, + VPAINT_TOOL_BLUR = 1, + VPAINT_TOOL_AVERAGE = 2, + VPAINT_TOOL_SMEAR = 3, +} eBrushVertexPaintTool; + +typedef enum eBrushWeightPaintTool { + WPAINT_TOOL_DRAW = 0, + WPAINT_TOOL_BLUR = 1, + WPAINT_TOOL_AVERAGE = 2, + WPAINT_TOOL_SMEAR = 3, +} eBrushWeightPaintTool; + +/* BrushGpencilSettings->brush type */ +typedef enum eBrushGPaintTool { + GPAINT_TOOL_DRAW = 0, + GPAINT_TOOL_FILL = 1, + GPAINT_TOOL_ERASE = 2, + GPAINT_TOOL_TINT = 3, +} eBrushGPaintTool; + +/* BrushGpencilSettings->brush type */ +typedef enum eBrushGPVertexTool { + GPVERTEX_TOOL_DRAW = 0, + GPVERTEX_TOOL_BLUR = 1, + GPVERTEX_TOOL_AVERAGE = 2, + GPVERTEX_TOOL_TINT = 3, + GPVERTEX_TOOL_SMEAR = 4, + GPVERTEX_TOOL_REPLACE = 5, +} eBrushGPVertexTool; + +/* BrushGpencilSettings->brush type */ +typedef enum eBrushGPSculptTool { + GPSCULPT_TOOL_SMOOTH = 0, + GPSCULPT_TOOL_THICKNESS = 1, + GPSCULPT_TOOL_STRENGTH = 2, + GPSCULPT_TOOL_GRAB = 3, + GPSCULPT_TOOL_PUSH = 4, + GPSCULPT_TOOL_TWIST = 5, + GPSCULPT_TOOL_PINCH = 6, + GPSCULPT_TOOL_RANDOMIZE = 7, + GPSCULPT_TOOL_CLONE = 8, +} eBrushGPSculptTool; + +/* BrushGpencilSettings->brush type */ +typedef enum eBrushGPWeightTool { + GPWEIGHT_TOOL_DRAW = 0, +} eBrushGPWeightTool; + +/* direction that the brush displaces along */ +enum { + SCULPT_DISP_DIR_AREA = 0, + SCULPT_DISP_DIR_VIEW = 1, + SCULPT_DISP_DIR_X = 2, + SCULPT_DISP_DIR_Y = 3, + SCULPT_DISP_DIR_Z = 4, +}; + +typedef enum { + BRUSH_MASK_DRAW = 0, + BRUSH_MASK_SMOOTH = 1, +} BrushMaskTool; + +/* blur kernel types, Brush.blur_mode */ +typedef enum eBlurKernelType { + KERNEL_GAUSSIAN = 0, + KERNEL_BOX = 1, +} eBlurKernelType; + +/* Brush.falloff_shape */ +enum { + PAINT_FALLOFF_SHAPE_SPHERE = 0, + PAINT_FALLOFF_SHAPE_TUBE = 1, +}; + +#define MAX_BRUSH_PIXEL_RADIUS 500 +#define GP_MAX_BRUSH_PIXEL_RADIUS 1000 + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h index 8332e4b45e1..31f19d8a193 100644 --- a/source/blender/makesdna/DNA_brush_types.h +++ b/source/blender/makesdna/DNA_brush_types.h @@ -24,6 +24,7 @@ #pragma once #include "DNA_ID.h" +#include "DNA_brush_enums.h" #include "DNA_curve_types.h" #include "DNA_texture_types.h" /* for MTex */ @@ -144,316 +145,6 @@ typedef struct BrushGpencilSettings { struct Material *material; } BrushGpencilSettings; -/* BrushGpencilSettings->preset_type. - * Use a range for each group and not continuous values.*/ -typedef enum eGPBrush_Presets { - GP_BRUSH_PRESET_UNKNOWN = 0, - - /* Draw 1-99. */ - GP_BRUSH_PRESET_AIRBRUSH = 1, - GP_BRUSH_PRESET_INK_PEN = 2, - GP_BRUSH_PRESET_INK_PEN_ROUGH = 3, - GP_BRUSH_PRESET_MARKER_BOLD = 4, - GP_BRUSH_PRESET_MARKER_CHISEL = 5, - GP_BRUSH_PRESET_PEN = 6, - GP_BRUSH_PRESET_PENCIL_SOFT = 7, - GP_BRUSH_PRESET_PENCIL = 8, - GP_BRUSH_PRESET_FILL_AREA = 9, - GP_BRUSH_PRESET_ERASER_SOFT = 10, - GP_BRUSH_PRESET_ERASER_HARD = 11, - GP_BRUSH_PRESET_ERASER_POINT = 12, - GP_BRUSH_PRESET_ERASER_STROKE = 13, - GP_BRUSH_PRESET_TINT = 14, - - /* Vertex Paint 100-199. */ - GP_BRUSH_PRESET_VERTEX_DRAW = 100, - GP_BRUSH_PRESET_VERTEX_BLUR = 101, - GP_BRUSH_PRESET_VERTEX_AVERAGE = 102, - GP_BRUSH_PRESET_VERTEX_SMEAR = 103, - GP_BRUSH_PRESET_VERTEX_REPLACE = 104, - - /* Sculpt 200-299. */ - GP_BRUSH_PRESET_SMOOTH_STROKE = 200, - GP_BRUSH_PRESET_STRENGTH_STROKE = 201, - GP_BRUSH_PRESET_THICKNESS_STROKE = 202, - GP_BRUSH_PRESET_GRAB_STROKE = 203, - GP_BRUSH_PRESET_PUSH_STROKE = 204, - GP_BRUSH_PRESET_TWIST_STROKE = 205, - GP_BRUSH_PRESET_PINCH_STROKE = 206, - GP_BRUSH_PRESET_RANDOMIZE_STROKE = 207, - GP_BRUSH_PRESET_CLONE_STROKE = 208, - - /* Weight Paint 300-399. */ - GP_BRUSH_PRESET_DRAW_WEIGHT = 300, -} eGPBrush_Presets; - -/* BrushGpencilSettings->flag */ -typedef enum eGPDbrush_Flag { - /* brush use pressure */ - GP_BRUSH_USE_PRESSURE = (1 << 0), - /* brush use pressure for alpha factor */ - GP_BRUSH_USE_STRENGTH_PRESSURE = (1 << 1), - /* brush use pressure for alpha factor */ - GP_BRUSH_USE_JITTER_PRESSURE = (1 << 2), - /* fill hide transparent */ - GP_BRUSH_FILL_HIDE = (1 << 6), - /* show fill help lines */ - GP_BRUSH_FILL_SHOW_HELPLINES = (1 << 7), - /* lazy mouse */ - GP_BRUSH_STABILIZE_MOUSE = (1 << 8), - /* lazy mouse override (internal only) */ - GP_BRUSH_STABILIZE_MOUSE_TEMP = (1 << 9), - /* default eraser brush for quick switch */ - GP_BRUSH_DEFAULT_ERASER = (1 << 10), - /* settings group */ - GP_BRUSH_GROUP_SETTINGS = (1 << 11), - /* Random settings group */ - GP_BRUSH_GROUP_RANDOM = (1 << 12), - /* Keep material assigned to brush */ - GP_BRUSH_MATERIAL_PINNED = (1 << 13), - /* Do not show fill color while drawing (no lasso mode) */ - GP_BRUSH_DISSABLE_LASSO = (1 << 14), - /* Do not erase strokes oLcluded */ - GP_BRUSH_OCCLUDE_ERASER = (1 << 15), - /* Post process trim stroke */ - GP_BRUSH_TRIM_STROKE = (1 << 16), -} eGPDbrush_Flag; - -typedef enum eGPDbrush_Flag2 { - /* Brush use random Hue at stroke level */ - GP_BRUSH_USE_HUE_AT_STROKE = (1 << 0), - /* Brush use random Saturation at stroke level */ - GP_BRUSH_USE_SAT_AT_STROKE = (1 << 1), - /* Brush use random Value at stroke level */ - GP_BRUSH_USE_VAL_AT_STROKE = (1 << 2), - /* Brush use random Pressure at stroke level */ - GP_BRUSH_USE_PRESS_AT_STROKE = (1 << 3), - /* Brush use random Strength at stroke level */ - GP_BRUSH_USE_STRENGTH_AT_STROKE = (1 << 4), - /* Brush use random UV at stroke level */ - GP_BRUSH_USE_UV_AT_STROKE = (1 << 5), - /* Brush use Hue random pressure */ - GP_BRUSH_USE_HUE_RAND_PRESS = (1 << 6), - /* Brush use Saturation random pressure */ - GP_BRUSH_USE_SAT_RAND_PRESS = (1 << 7), - /* Brush use Value random pressure */ - GP_BRUSH_USE_VAL_RAND_PRESS = (1 << 8), - /* Brush use Pressure random pressure */ - GP_BRUSH_USE_PRESSURE_RAND_PRESS = (1 << 9), - /* Brush use Strength random pressure */ - GP_BRUSH_USE_STRENGTH_RAND_PRESS = (1 << 10), - /* Brush use UV random pressure */ - GP_BRUSH_USE_UV_RAND_PRESS = (1 << 11), -} eGPDbrush_Flag2; - -/* BrushGpencilSettings->gp_fill_draw_mode */ -typedef enum eGP_FillDrawModes { - GP_FILL_DMODE_BOTH = 0, - GP_FILL_DMODE_STROKE = 1, - GP_FILL_DMODE_CONTROL = 2, -} eGP_FillDrawModes; - -/* BrushGpencilSettings->fill_layer_mode */ -typedef enum eGP_FillLayerModes { - GP_FILL_GPLMODE_VISIBLE = 0, - GP_FILL_GPLMODE_ACTIVE = 1, - GP_FILL_GPLMODE_ALL_ABOVE = 2, - GP_FILL_GPLMODE_ALL_BELOW = 3, - GP_FILL_GPLMODE_ABOVE = 4, - GP_FILL_GPLMODE_BELOW = 5, -} eGP_FillLayerModes; - -/* BrushGpencilSettings->gp_eraser_mode */ -typedef enum eGP_BrushEraserMode { - GP_BRUSH_ERASER_SOFT = 0, - GP_BRUSH_ERASER_HARD = 1, - GP_BRUSH_ERASER_STROKE = 2, -} eGP_BrushEraserMode; - -/* BrushGpencilSettings->brush_draw_mode */ -typedef enum eGP_BrushMode { - GP_BRUSH_MODE_ACTIVE = 0, - GP_BRUSH_MODE_MATERIAL = 1, - GP_BRUSH_MODE_VERTEXCOLOR = 2, -} eGP_BrushMode; - -/* BrushGpencilSettings default brush icons */ -typedef enum eGP_BrushIcons { - GP_BRUSH_ICON_PENCIL = 1, - GP_BRUSH_ICON_PEN = 2, - GP_BRUSH_ICON_INK = 3, - GP_BRUSH_ICON_INKNOISE = 4, - GP_BRUSH_ICON_BLOCK = 5, - GP_BRUSH_ICON_MARKER = 6, - GP_BRUSH_ICON_FILL = 7, - GP_BRUSH_ICON_ERASE_SOFT = 8, - GP_BRUSH_ICON_ERASE_HARD = 9, - GP_BRUSH_ICON_ERASE_STROKE = 10, - GP_BRUSH_ICON_AIRBRUSH = 11, - GP_BRUSH_ICON_CHISEL = 12, - GP_BRUSH_ICON_TINT = 13, - GP_BRUSH_ICON_VERTEX_DRAW = 14, - GP_BRUSH_ICON_VERTEX_BLUR = 15, - GP_BRUSH_ICON_VERTEX_AVERAGE = 16, - GP_BRUSH_ICON_VERTEX_SMEAR = 17, - GP_BRUSH_ICON_VERTEX_REPLACE = 18, - GP_BRUSH_ICON_GPBRUSH_SMOOTH = 19, - GP_BRUSH_ICON_GPBRUSH_THICKNESS = 20, - GP_BRUSH_ICON_GPBRUSH_STRENGTH = 21, - GP_BRUSH_ICON_GPBRUSH_RANDOMIZE = 22, - GP_BRUSH_ICON_GPBRUSH_GRAB = 23, - GP_BRUSH_ICON_GPBRUSH_PUSH = 24, - GP_BRUSH_ICON_GPBRUSH_TWIST = 25, - GP_BRUSH_ICON_GPBRUSH_PINCH = 26, - GP_BRUSH_ICON_GPBRUSH_CLONE = 27, - GP_BRUSH_ICON_GPBRUSH_WEIGHT = 28, -} eGP_BrushIcons; - -typedef enum eBrushCurvePreset { - BRUSH_CURVE_CUSTOM = 0, - BRUSH_CURVE_SMOOTH = 1, - BRUSH_CURVE_SPHERE = 2, - BRUSH_CURVE_ROOT = 3, - BRUSH_CURVE_SHARP = 4, - BRUSH_CURVE_LIN = 5, - BRUSH_CURVE_POW4 = 6, - BRUSH_CURVE_INVSQUARE = 7, - BRUSH_CURVE_CONSTANT = 8, - BRUSH_CURVE_SMOOTHER = 9, -} eBrushCurvePreset; - -typedef enum eBrushDeformTarget { - BRUSH_DEFORM_TARGET_GEOMETRY = 0, - BRUSH_DEFORM_TARGET_CLOTH_SIM = 1, -} eBrushDeformTarget; - -typedef enum eBrushElasticDeformType { - BRUSH_ELASTIC_DEFORM_GRAB = 0, - BRUSH_ELASTIC_DEFORM_GRAB_BISCALE = 1, - BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE = 2, - BRUSH_ELASTIC_DEFORM_SCALE = 3, - BRUSH_ELASTIC_DEFORM_TWIST = 4, -} eBrushElasticDeformType; - -typedef enum eBrushClothDeformType { - BRUSH_CLOTH_DEFORM_DRAG = 0, - BRUSH_CLOTH_DEFORM_PUSH = 1, - BRUSH_CLOTH_DEFORM_GRAB = 2, - BRUSH_CLOTH_DEFORM_PINCH_POINT = 3, - BRUSH_CLOTH_DEFORM_PINCH_PERPENDICULAR = 4, - BRUSH_CLOTH_DEFORM_INFLATE = 5, - BRUSH_CLOTH_DEFORM_EXPAND = 6, - BRUSH_CLOTH_DEFORM_SNAKE_HOOK = 7, -} eBrushClothDeformType; - -typedef enum eBrushSmoothDeformType { - BRUSH_SMOOTH_DEFORM_LAPLACIAN = 0, - BRUSH_SMOOTH_DEFORM_SURFACE = 1, -} eBrushSmoothDeformType; - -typedef enum eBrushClothForceFalloffType { - BRUSH_CLOTH_FORCE_FALLOFF_RADIAL = 0, - BRUSH_CLOTH_FORCE_FALLOFF_PLANE = 1, -} eBrushClothForceFalloffType; - -typedef enum eBrushClothSimulationAreaType { - BRUSH_CLOTH_SIMULATION_AREA_LOCAL = 0, - BRUSH_CLOTH_SIMULATION_AREA_GLOBAL = 1, - BRUSH_CLOTH_SIMULATION_AREA_DYNAMIC = 2, -} eBrushClothSimulationAreaType; - -typedef enum eBrushPoseDeformType { - BRUSH_POSE_DEFORM_ROTATE_TWIST = 0, - BRUSH_POSE_DEFORM_SCALE_TRASLATE = 1, - BRUSH_POSE_DEFORM_SQUASH_STRETCH = 2, -} eBrushPoseDeformType; - -typedef enum eBrushPoseOriginType { - BRUSH_POSE_ORIGIN_TOPOLOGY = 0, - BRUSH_POSE_ORIGIN_FACE_SETS = 1, - BRUSH_POSE_ORIGIN_FACE_SETS_FK = 2, -} eBrushPoseOriginType; - -typedef enum eBrushSmearDeformType { - BRUSH_SMEAR_DEFORM_DRAG = 0, - BRUSH_SMEAR_DEFORM_PINCH = 1, - BRUSH_SMEAR_DEFORM_EXPAND = 2, -} eBrushSmearDeformType; - -typedef enum eBrushSlideDeformType { - BRUSH_SLIDE_DEFORM_DRAG = 0, - BRUSH_SLIDE_DEFORM_PINCH = 1, - BRUSH_SLIDE_DEFORM_EXPAND = 2, -} eBrushSlideDeformType; - -typedef enum eBrushBoundaryDeformType { - BRUSH_BOUNDARY_DEFORM_BEND = 0, - BRUSH_BOUNDARY_DEFORM_EXPAND = 1, - BRUSH_BOUNDARY_DEFORM_INFLATE = 2, - BRUSH_BOUNDARY_DEFORM_GRAB = 3, - BRUSH_BOUNDARY_DEFORM_TWIST = 4, - BRUSH_BOUNDARY_DEFORM_SMOOTH = 5, -} eBrushBushBoundaryDeformType; - -typedef enum eBrushBoundaryFalloffType { - BRUSH_BOUNDARY_FALLOFF_CONSTANT = 0, - BRUSH_BOUNDARY_FALLOFF_RADIUS = 1, - BRUSH_BOUNDARY_FALLOFF_LOOP = 2, - BRUSH_BOUNDARY_FALLOFF_LOOP_INVERT = 3, -} eBrushBoundaryFalloffType; - -/* Gpencilsettings.Vertex_mode */ -typedef enum eGp_Vertex_Mode { - /* Affect to Stroke only. */ - GPPAINT_MODE_STROKE = 0, - /* Affect to Fill only. */ - GPPAINT_MODE_FILL = 1, - /* Affect to both. */ - GPPAINT_MODE_BOTH = 2, -} eGp_Vertex_Mode; - -/* sculpt_flag */ -typedef enum eGP_Sculpt_Flag { - /* invert the effect of the brush */ - GP_SCULPT_FLAG_INVERT = (1 << 0), - /* smooth brush affects pressure values as well */ - GP_SCULPT_FLAG_SMOOTH_PRESSURE = (1 << 2), - /* temporary invert action */ - GP_SCULPT_FLAG_TMP_INVERT = (1 << 3), -} eGP_Sculpt_Flag; - -/* sculpt_mode_flag */ -typedef enum eGP_Sculpt_Mode_Flag { - /* apply brush to position */ - GP_SCULPT_FLAGMODE_APPLY_POSITION = (1 << 0), - /* apply brush to strength */ - GP_SCULPT_FLAGMODE_APPLY_STRENGTH = (1 << 1), - /* apply brush to thickness */ - GP_SCULPT_FLAGMODE_APPLY_THICKNESS = (1 << 2), - /* apply brush to uv data */ - GP_SCULPT_FLAGMODE_APPLY_UV = (1 << 3), -} eGP_Sculpt_Mode_Flag; - -typedef enum eAutomasking_flag { - BRUSH_AUTOMASKING_TOPOLOGY = (1 << 0), - BRUSH_AUTOMASKING_FACE_SETS = (1 << 1), - BRUSH_AUTOMASKING_BOUNDARY_EDGES = (1 << 2), - BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS = (1 << 3), -} eAutomasking_flag; - -typedef enum ePaintBrush_flag { - BRUSH_PAINT_HARDNESS_PRESSURE = (1 << 0), - BRUSH_PAINT_HARDNESS_PRESSURE_INVERT = (1 << 1), - BRUSH_PAINT_FLOW_PRESSURE = (1 << 2), - BRUSH_PAINT_FLOW_PRESSURE_INVERT = (1 << 3), - BRUSH_PAINT_WET_MIX_PRESSURE = (1 << 4), - BRUSH_PAINT_WET_MIX_PRESSURE_INVERT = (1 << 5), - BRUSH_PAINT_WET_PERSISTENCE_PRESSURE = (1 << 6), - BRUSH_PAINT_WET_PERSISTENCE_PRESSURE_INVERT = (1 << 7), - BRUSH_PAINT_DENSITY_PRESSURE = (1 << 8), - BRUSH_PAINT_DENSITY_PRESSURE_INVERT = (1 << 9), -} ePaintBrush_flag; - typedef struct Brush { ID id; @@ -573,7 +264,7 @@ typedef struct Brush { char gpencil_sculpt_tool; /** Active grease pencil weight tool. */ char gpencil_weight_tool; - char _pad1[2]; + char _pad1[6]; float autosmooth_factor; @@ -609,6 +300,9 @@ typedef struct Brush { int elastic_deform_type; float elastic_deform_volume_preservation; + /* snake hook */ + int snake_hook_deform_type; + /* pose */ int pose_deform_type; float pose_offset; @@ -681,7 +375,7 @@ typedef struct Brush { typedef struct tPaletteColorHSV { float rgb[3]; float value; - float h; + float h; float s; float v; } tPaletteColorHSV; @@ -719,277 +413,6 @@ typedef struct PaintCurve { int add_index; } PaintCurve; -/* Brush.gradient_source */ -typedef enum eBrushGradientSourceStroke { - BRUSH_GRADIENT_PRESSURE = 0, /* gradient from pressure */ - BRUSH_GRADIENT_SPACING_REPEAT = 1, /* gradient from spacing */ - BRUSH_GRADIENT_SPACING_CLAMP = 2, /* gradient from spacing */ -} eBrushGradientSourceStroke; - -typedef enum eBrushGradientSourceFill { - BRUSH_GRADIENT_LINEAR = 0, /* gradient from pressure */ - BRUSH_GRADIENT_RADIAL = 1, /* gradient from spacing */ -} eBrushGradientSourceFill; - -/* Brush.flag */ -typedef enum eBrushFlags { - BRUSH_AIRBRUSH = (1 << 0), - BRUSH_INVERT_TO_SCRAPE_FILL = (1 << 1), - BRUSH_ALPHA_PRESSURE = (1 << 2), - BRUSH_SIZE_PRESSURE = (1 << 3), - BRUSH_JITTER_PRESSURE = (1 << 4), - BRUSH_SPACING_PRESSURE = (1 << 5), - BRUSH_ORIGINAL_PLANE = (1 << 6), - BRUSH_GRAB_ACTIVE_VERTEX = (1 << 7), - BRUSH_ANCHORED = (1 << 8), - BRUSH_DIR_IN = (1 << 9), - BRUSH_SPACE = (1 << 10), - BRUSH_SMOOTH_STROKE = (1 << 11), - BRUSH_PERSISTENT = (1 << 12), - BRUSH_ACCUMULATE = (1 << 13), - BRUSH_LOCK_ALPHA = (1 << 14), - BRUSH_ORIGINAL_NORMAL = (1 << 15), - BRUSH_OFFSET_PRESSURE = (1 << 16), - BRUSH_SCENE_SPACING = (1 << 17), - BRUSH_SPACE_ATTEN = (1 << 18), - BRUSH_ADAPTIVE_SPACE = (1 << 19), - BRUSH_LOCK_SIZE = (1 << 20), - BRUSH_USE_GRADIENT = (1 << 21), - BRUSH_EDGE_TO_EDGE = (1 << 22), - BRUSH_DRAG_DOT = (1 << 23), - BRUSH_INVERSE_SMOOTH_PRESSURE = (1 << 24), - BRUSH_FRONTFACE_FALLOFF = (1 << 25), - BRUSH_PLANE_TRIM = (1 << 26), - BRUSH_FRONTFACE = (1 << 27), - BRUSH_CUSTOM_ICON = (1 << 28), - BRUSH_LINE = (1 << 29), - BRUSH_ABSOLUTE_JITTER = (1 << 30), - BRUSH_CURVE = (1u << 31), -} eBrushFlags; - -/* Brush.sampling_flag */ -typedef enum eBrushSamplingFlags { - BRUSH_PAINT_ANTIALIASING = (1 << 0), -} eBrushSamplingFlags; - -/* Brush.flag2 */ -typedef enum eBrushFlags2 { - BRUSH_MULTIPLANE_SCRAPE_DYNAMIC = (1 << 0), - BRUSH_MULTIPLANE_SCRAPE_PLANES_PREVIEW = (1 << 1), - BRUSH_POSE_IK_ANCHORED = (1 << 2), - BRUSH_USE_CONNECTED_ONLY = (1 << 3), - BRUSH_CLOTH_PIN_SIMULATION_BOUNDARY = (1 << 4), - BRUSH_POSE_USE_LOCK_ROTATION = (1 << 5), - BRUSH_CLOTH_USE_COLLISION = (1 << 6), - BRUSH_AREA_RADIUS_PRESSURE = (1 << 7), - BRUSH_GRAB_SILHOUETTE = (1 << 8), -} eBrushFlags2; - -typedef enum { - BRUSH_MASK_PRESSURE_RAMP = (1 << 1), - BRUSH_MASK_PRESSURE_CUTOFF = (1 << 2), -} BrushMaskPressureFlags; - -/* Brush.overlay_flags */ -typedef enum eOverlayFlags { - BRUSH_OVERLAY_CURSOR = (1), - BRUSH_OVERLAY_PRIMARY = (1 << 1), - BRUSH_OVERLAY_SECONDARY = (1 << 2), - BRUSH_OVERLAY_CURSOR_OVERRIDE_ON_STROKE = (1 << 3), - BRUSH_OVERLAY_PRIMARY_OVERRIDE_ON_STROKE = (1 << 4), - BRUSH_OVERLAY_SECONDARY_OVERRIDE_ON_STROKE = (1 << 5), -} eOverlayFlags; - -#define BRUSH_OVERLAY_OVERRIDE_MASK \ - (BRUSH_OVERLAY_CURSOR_OVERRIDE_ON_STROKE | BRUSH_OVERLAY_PRIMARY_OVERRIDE_ON_STROKE | \ - BRUSH_OVERLAY_SECONDARY_OVERRIDE_ON_STROKE) - -/* Brush.sculpt_tool */ -typedef enum eBrushSculptTool { - SCULPT_TOOL_DRAW = 1, - SCULPT_TOOL_SMOOTH = 2, - SCULPT_TOOL_PINCH = 3, - SCULPT_TOOL_INFLATE = 4, - SCULPT_TOOL_GRAB = 5, - SCULPT_TOOL_LAYER = 6, - SCULPT_TOOL_FLATTEN = 7, - SCULPT_TOOL_CLAY = 8, - SCULPT_TOOL_FILL = 9, - SCULPT_TOOL_SCRAPE = 10, - SCULPT_TOOL_NUDGE = 11, - SCULPT_TOOL_THUMB = 12, - SCULPT_TOOL_SNAKE_HOOK = 13, - SCULPT_TOOL_ROTATE = 14, - SCULPT_TOOL_SIMPLIFY = 15, - SCULPT_TOOL_CREASE = 16, - SCULPT_TOOL_BLOB = 17, - SCULPT_TOOL_CLAY_STRIPS = 18, - SCULPT_TOOL_MASK = 19, - SCULPT_TOOL_DRAW_SHARP = 20, - SCULPT_TOOL_ELASTIC_DEFORM = 21, - SCULPT_TOOL_POSE = 22, - SCULPT_TOOL_MULTIPLANE_SCRAPE = 23, - SCULPT_TOOL_SLIDE_RELAX = 24, - SCULPT_TOOL_CLAY_THUMB = 25, - SCULPT_TOOL_CLOTH = 26, - SCULPT_TOOL_DRAW_FACE_SETS = 27, - SCULPT_TOOL_PAINT = 28, - SCULPT_TOOL_SMEAR = 29, - SCULPT_TOOL_BOUNDARY = 30, - SCULPT_TOOL_DISPLACEMENT_ERASER = 31, - SCULPT_TOOL_VCOL_BOUNDARY = 32, -} eBrushSculptTool; - -/* Brush.uv_sculpt_tool */ -typedef enum eBrushUVSculptTool { - UV_SCULPT_TOOL_GRAB = 0, - UV_SCULPT_TOOL_RELAX = 1, - UV_SCULPT_TOOL_PINCH = 2, -} eBrushUVSculptTool; - -/** When #BRUSH_ACCUMULATE is used */ -#define SCULPT_TOOL_HAS_ACCUMULATE(t) \ - ELEM(t, \ - SCULPT_TOOL_DRAW, \ - SCULPT_TOOL_DRAW_SHARP, \ - SCULPT_TOOL_SLIDE_RELAX, \ - SCULPT_TOOL_CREASE, \ - SCULPT_TOOL_BLOB, \ - SCULPT_TOOL_INFLATE, \ - SCULPT_TOOL_CLAY, \ - SCULPT_TOOL_CLAY_STRIPS, \ - SCULPT_TOOL_CLAY_THUMB, \ - SCULPT_TOOL_ROTATE, \ - SCULPT_TOOL_SCRAPE, \ - SCULPT_TOOL_FLATTEN) - -#define SCULPT_TOOL_HAS_NORMAL_WEIGHT(t) \ - ELEM(t, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_ELASTIC_DEFORM) - -#define SCULPT_TOOL_HAS_RAKE(t) ELEM(t, SCULPT_TOOL_SNAKE_HOOK) - -#define SCULPT_TOOL_HAS_DYNTOPO(t) \ - (ELEM(t, /* These brushes, as currently coded, cannot support dynamic topology */ \ - SCULPT_TOOL_GRAB, \ - SCULPT_TOOL_ROTATE, \ - SCULPT_TOOL_CLOTH, \ - SCULPT_TOOL_THUMB, \ - SCULPT_TOOL_LAYER, \ - SCULPT_TOOL_DISPLACEMENT_ERASER, \ - SCULPT_TOOL_SLIDE_RELAX, \ - SCULPT_TOOL_ELASTIC_DEFORM, \ - SCULPT_TOOL_BOUNDARY, \ - SCULPT_TOOL_POSE, \ - SCULPT_TOOL_PAINT, \ - SCULPT_TOOL_VCOL_BOUNDARY, \ - SCULPT_TOOL_DRAW_FACE_SETS, \ - SCULPT_TOOL_SMEAR, \ -\ - /* These brushes could handle dynamic topology, \ \ - * but user feedback indicates it's better not to */ \ - SCULPT_TOOL_SMOOTH, \ - SCULPT_TOOL_MASK) == 0) - -#define SCULPT_TOOL_HAS_TOPOLOGY_RAKE(t) \ - (ELEM(t, /* These brushes, as currently coded, cannot support topology rake. */ \ - SCULPT_TOOL_GRAB, \ - SCULPT_TOOL_ROTATE, \ - SCULPT_TOOL_THUMB, \ - SCULPT_TOOL_DISPLACEMENT_ERASER, \ - SCULPT_TOOL_SLIDE_RELAX, \ - SCULPT_TOOL_MASK) == 0) - -#define SCULPT_TOOL_HAS_VCOL_BOUNDARY_SMOOTH(t) ELEM(t, SCULPT_TOOL_PAINT) - -/* ImagePaintSettings.tool */ -typedef enum eBrushImagePaintTool { - PAINT_TOOL_DRAW = 0, - PAINT_TOOL_SOFTEN = 1, - PAINT_TOOL_SMEAR = 2, - PAINT_TOOL_CLONE = 3, - PAINT_TOOL_FILL = 4, - PAINT_TOOL_MASK = 5, -} eBrushImagePaintTool; - -typedef enum eBrushVertexPaintTool { - VPAINT_TOOL_DRAW = 0, - VPAINT_TOOL_BLUR = 1, - VPAINT_TOOL_AVERAGE = 2, - VPAINT_TOOL_SMEAR = 3, -} eBrushVertexPaintTool; - -typedef enum eBrushWeightPaintTool { - WPAINT_TOOL_DRAW = 0, - WPAINT_TOOL_BLUR = 1, - WPAINT_TOOL_AVERAGE = 2, - WPAINT_TOOL_SMEAR = 3, -} eBrushWeightPaintTool; - -/* BrushGpencilSettings->brush type */ -typedef enum eBrushGPaintTool { - GPAINT_TOOL_DRAW = 0, - GPAINT_TOOL_FILL = 1, - GPAINT_TOOL_ERASE = 2, - GPAINT_TOOL_TINT = 3, -} eBrushGPaintTool; - -/* BrushGpencilSettings->brush type */ -typedef enum eBrushGPVertexTool { - GPVERTEX_TOOL_DRAW = 0, - GPVERTEX_TOOL_BLUR = 1, - GPVERTEX_TOOL_AVERAGE = 2, - GPVERTEX_TOOL_TINT = 3, - GPVERTEX_TOOL_SMEAR = 4, - GPVERTEX_TOOL_REPLACE = 5, -} eBrushGPVertexTool; - -/* BrushGpencilSettings->brush type */ -typedef enum eBrushGPSculptTool { - GPSCULPT_TOOL_SMOOTH = 0, - GPSCULPT_TOOL_THICKNESS = 1, - GPSCULPT_TOOL_STRENGTH = 2, - GPSCULPT_TOOL_GRAB = 3, - GPSCULPT_TOOL_PUSH = 4, - GPSCULPT_TOOL_TWIST = 5, - GPSCULPT_TOOL_PINCH = 6, - GPSCULPT_TOOL_RANDOMIZE = 7, - GPSCULPT_TOOL_CLONE = 8, -} eBrushGPSculptTool; - -/* BrushGpencilSettings->brush type */ -typedef enum eBrushGPWeightTool { - GPWEIGHT_TOOL_DRAW = 0, -} eBrushGPWeightTool; - -/* direction that the brush displaces along */ -enum { - SCULPT_DISP_DIR_AREA = 0, - SCULPT_DISP_DIR_VIEW = 1, - SCULPT_DISP_DIR_X = 2, - SCULPT_DISP_DIR_Y = 3, - SCULPT_DISP_DIR_Z = 4, -}; - -typedef enum { - BRUSH_MASK_DRAW = 0, - BRUSH_MASK_SMOOTH = 1, -} BrushMaskTool; - -/* blur kernel types, Brush.blur_mode */ -typedef enum eBlurKernelType { - KERNEL_GAUSSIAN = 0, - KERNEL_BOX = 1, -} eBlurKernelType; - -/* Brush.falloff_shape */ -enum { - PAINT_FALLOFF_SHAPE_SPHERE = 0, - PAINT_FALLOFF_SHAPE_TUBE = 1, -}; - -#define MAX_BRUSH_PIXEL_RADIUS 500 -#define GP_MAX_BRUSH_PIXEL_RADIUS 1000 - #ifdef __cplusplus } #endif diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h index ae0bb20e529..e3b5ecfac04 100644 --- a/source/blender/makesdna/DNA_customdata_types.h +++ b/source/blender/makesdna/DNA_customdata_types.h @@ -75,8 +75,7 @@ typedef struct CustomData { * MUST be >= CD_NUMTYPES, but we cant use a define here. * Correct size is ensured in CustomData_update_typemap assert(). */ - int typemap[50]; - char _pad[4]; + int typemap[51]; /** Number of layers, size of layers array. */ int totlayer, maxlayer; /** In editmode, total size of all data layers. */ @@ -156,7 +155,9 @@ typedef enum CustomDataType { CD_PROP_FLOAT3 = 48, CD_PROP_FLOAT2 = 49, - CD_NUMTYPES = 50, + CD_PROP_BOOL = 50, + + CD_NUMTYPES = 51, } CustomDataType; /* Bits for CustomDataMask */ @@ -208,6 +209,7 @@ typedef enum CustomDataType { #define CD_MASK_PROP_COLOR (1ULL << CD_PROP_COLOR) #define CD_MASK_PROP_FLOAT3 (1ULL << CD_PROP_FLOAT3) #define CD_MASK_PROP_FLOAT2 (1ULL << CD_PROP_FLOAT2) +#define CD_MASK_PROP_BOOL (1ULL << CD_PROP_BOOL) /** Multires loop data. */ #define CD_MASK_MULTIRES_GRIDS (CD_MASK_MDISPS | CD_GRID_PAINT_MASK) @@ -218,7 +220,7 @@ typedef enum CustomDataType { /* All generic attributes. */ #define CD_MASK_PROP_ALL \ (CD_MASK_PROP_FLOAT | CD_MASK_PROP_FLOAT2 | CD_MASK_PROP_FLOAT3 | CD_MASK_PROP_INT32 | \ - CD_MASK_PROP_COLOR | CD_MASK_PROP_STRING | CD_MASK_MLOOPCOL) + CD_MASK_PROP_COLOR | CD_MASK_PROP_STRING | CD_MASK_MLOOPCOL | CD_MASK_PROP_BOOL) typedef struct CustomData_MeshMasks { uint64_t vmask; diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h index bd5afc457ac..9ac40495887 100644 --- a/source/blender/makesdna/DNA_gpencil_modifier_types.h +++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h @@ -351,6 +351,7 @@ typedef enum eArrayGpencil_Flag { GP_ARRAY_USE_OFFSET = (1 << 7), GP_ARRAY_USE_RELATIVE = (1 << 8), GP_ARRAY_USE_OB_OFFSET = (1 << 9), + GP_ARRAY_UNIFORM_RANDOM_SCALE = (1 << 10), } eArrayGpencil_Flag; typedef struct BuildGpencilModifierData { diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h index 212f0bfa1c9..949b0bb5bf5 100644 --- a/source/blender/makesdna/DNA_gpencil_types.h +++ b/source/blender/makesdna/DNA_gpencil_types.h @@ -32,8 +32,8 @@ extern "C" { #endif struct AnimData; -struct MDeformVert; struct Curve; +struct MDeformVert; #define GP_DEFAULT_PIX_FACTOR 1.0f #define GP_DEFAULT_GRID_LINES 4 diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h index 4edf06f90f7..eb03e047c90 100644 --- a/source/blender/makesdna/DNA_image_types.h +++ b/source/blender/makesdna/DNA_image_types.h @@ -151,12 +151,13 @@ typedef struct Image { int lastframe; /* GPU texture flag. */ + /* Contains `ImagePartialRefresh`. */ + ListBase gpu_refresh_areas; int gpuframenr; short gpuflag; short gpu_pass; short gpu_layer; - short gpu_slot; - char _pad2[4]; + char _pad2[6]; /** Deprecated. */ struct PackedFile *packedfile DNA_DEPRECATED; @@ -223,8 +224,10 @@ enum { enum { /** GPU texture needs to be refreshed. */ IMA_GPU_REFRESH = (1 << 0), + /** GPU texture needs to be partially refreshed. */ + IMA_GPU_PARTIAL_REFRESH = (1 << 1), /** All mipmap levels in OpenGL texture set? */ - IMA_GPU_MIPMAP_COMPLETE = (1 << 1), + IMA_GPU_MIPMAP_COMPLETE = (1 << 2), }; /* Image.source, where the image comes from */ diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h index 6a91f4857b4..828c6ff2a51 100644 --- a/source/blender/makesdna/DNA_layer_types.h +++ b/source/blender/makesdna/DNA_layer_types.h @@ -40,8 +40,8 @@ typedef enum eViewLayerEEVEEPassType { EEVEE_RENDER_PASS_DIFFUSE_COLOR = (1 << 5), EEVEE_RENDER_PASS_SPECULAR_LIGHT = (1 << 6), EEVEE_RENDER_PASS_SPECULAR_COLOR = (1 << 7), - EEVEE_RENDER_PASS_VOLUME_TRANSMITTANCE = (1 << 8), - EEVEE_RENDER_PASS_VOLUME_SCATTER = (1 << 9), + EEVEE_RENDER_PASS_UNUSED_8 = (1 << 8), + EEVEE_RENDER_PASS_VOLUME_LIGHT = (1 << 9), EEVEE_RENDER_PASS_EMIT = (1 << 10), EEVEE_RENDER_PASS_ENVIRONMENT = (1 << 11), EEVEE_RENDER_PASS_SHADOW = (1 << 12), diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index 04fbc030ed9..c2337b28e54 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -35,7 +35,6 @@ struct AnimData; struct BVHCache; struct Ipo; struct Key; -struct LinkNode; struct MCol; struct MEdge; struct MFace; @@ -44,7 +43,6 @@ struct MLoopCol; struct MLoopTri; struct MLoopUV; struct MPoly; -struct MPropCol; struct MVert; struct Material; struct Mesh; diff --git a/source/blender/makesdna/DNA_modifier_defaults.h b/source/blender/makesdna/DNA_modifier_defaults.h index f73f43ddade..fcb582ef837 100644 --- a/source/blender/makesdna/DNA_modifier_defaults.h +++ b/source/blender/makesdna/DNA_modifier_defaults.h @@ -503,8 +503,8 @@ .random_position = 0.0f, \ .rotation = 0.0f, \ .random_rotation = 0.0f, \ - .particle_offset = 1.0f, \ - .particle_amount = 0.0f, \ + .particle_offset = 0.0f, \ + .particle_amount = 1.0f, \ .index_layer_name = "", \ .value_layer_name = "", \ } @@ -801,6 +801,7 @@ #define _DNA_DEFAULT_WeldModifierData \ { \ .merge_dist = 0.001f, \ + .mode = MOD_WELD_MODE_ALL, \ .defgrp_name = "", \ } diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 2a0154a97f0..83ecd5ee208 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -2005,7 +2005,8 @@ typedef struct WeldModifierData { /* Name of vertex group to use to mask, MAX_VGROUP_NAME. */ char defgrp_name[64]; - short flag; + char mode; + char flag; char _pad[2]; } WeldModifierData; @@ -2014,6 +2015,12 @@ enum { MOD_WELD_INVERT_VGROUP = (1 << 0), }; +/* #WeldModifierData.mode */ +enum { + MOD_WELD_MODE_ALL = 0, + MOD_WELD_MODE_CONNECTED = 1, +}; + typedef struct DataTransferModifierData { ModifierData modifier; diff --git a/source/blender/makesdna/DNA_movieclip_types.h b/source/blender/makesdna/DNA_movieclip_types.h index 2b1fd546450..11cdb48edf0 100644 --- a/source/blender/makesdna/DNA_movieclip_types.h +++ b/source/blender/makesdna/DNA_movieclip_types.h @@ -24,8 +24,8 @@ #pragma once #include "DNA_ID.h" -#include "DNA_color_types.h" /* for color management */ -#include "DNA_tracking_types.h" +#include "DNA_color_types.h" /* for color management */ +#include "DNA_tracking_types.h" /* for #MovieTracking */ #ifdef __cplusplus extern "C" { diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 29c83d2d4ed..64dd489b850 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -25,15 +25,15 @@ #include "DNA_ID.h" #include "DNA_listBase.h" -#include "DNA_scene_types.h" -#include "DNA_texture_types.h" -#include "DNA_vec_types.h" +#include "DNA_scene_types.h" /* for #ImageFormatData */ +#include "DNA_vec_types.h" /* for #rctf */ #ifdef __cplusplus extern "C" { #endif struct AnimData; +struct Collection; struct ID; struct Image; struct ListBase; @@ -160,6 +160,7 @@ typedef enum eNodeSocketDatatype { SOCK_OBJECT = 8, SOCK_IMAGE = 9, SOCK_GEOMETRY = 10, + SOCK_COLLECTION = 11, } eNodeSocketDatatype; /* socket shape */ @@ -217,15 +218,14 @@ typedef struct bNode { char name[64]; int flag; short type; - char _pad[2]; /** Both for dependency and sorting. */ short done, level; - /** Lasty: check preview render status, menunr: browse ID blocks. */ - short lasty, menunr; - /** For groupnode, offset in global caller stack. */ - short stack_index; - /** Number of this node in list, used for UI exec events. */ - short nr; + + /** Used as a boolean for execution. */ + uint8_t need_exec; + + char _pad[1]; + /** Custom user-defined color. */ float color[3]; @@ -263,10 +263,8 @@ typedef struct bNode { short custom1, custom2; float custom3, custom4; - /** Need_exec is set as UI execution event, exec is flag during exec. */ - short need_exec, exec; - /** Optional extra storage for use in thread (read only then!). */ - void *threaddata; + char _pad1[4]; + /** Entire boundbox (worldspace). */ rctf totr; /** Optional buttons area. */ @@ -580,6 +578,10 @@ typedef struct bNodeSocketValueImage { struct Image *value; } bNodeSocketValueImage; +typedef struct bNodeSocketValueCollection { + struct Collection *value; +} bNodeSocketValueCollection; + /* data structs, for node->storage */ enum { CMP_NODE_MASKTYPE_ADD = 0, @@ -1046,10 +1048,20 @@ typedef struct NodeSunBeams { float ray_length; } NodeSunBeams; +typedef struct CryptomatteEntry { + struct CryptomatteEntry *next, *prev; + float encoded_hash; + /** MAX_NAME. */ + char name[64]; + char _pad[4]; +} CryptomatteEntry; + typedef struct NodeCryptomatte { float add[3]; float remove[3]; - char *matte_id; + char *matte_id DNA_DEPRECATED; + /* Contains `CryptomatteEntry`. */ + ListBase entries; int num_inputs; char _pad[4]; } NodeCryptomatte; @@ -1059,6 +1071,46 @@ typedef struct NodeDenoise { char _pad[7]; } NodeDenoise; +typedef struct NodeAttributeCompare { + /* FloatCompareOperation. */ + uint8_t operation; + + /* GeometryNodeAttributeInputMode */ + uint8_t input_type_a; + uint8_t input_type_b; + + char _pad[5]; +} NodeAttributeCompare; + +typedef struct NodeAttributeMath { + /* e.g. NODE_MATH_ADD. */ + uint8_t operation; + + /* GeometryNodeAttributeInputMode */ + uint8_t input_type_a; + uint8_t input_type_b; + + char _pad[5]; +} NodeAttributeMath; + +typedef struct NodeAttributeMix { + /* e.g. MA_RAMP_BLEND. */ + uint8_t blend_type; + + /* GeometryNodeAttributeInputMode */ + uint8_t input_type_factor; + uint8_t input_type_a; + uint8_t input_type_b; +} NodeAttributeMix; + +typedef struct NodeAttributeColorRamp { + ColorBand color_ramp; +} NodeAttributeColorRamp; + +typedef struct NodeInputVector { + float vector[3]; +} NodeInputVector; + /* script node mode */ #define NODE_SCRIPT_INTERNAL 0 #define NODE_SCRIPT_EXTERNAL 1 @@ -1336,14 +1388,14 @@ enum { }; /* Float compare node operations. */ -enum { +typedef enum FloatCompareOperation { NODE_FLOAT_COMPARE_LESS_THAN = 0, NODE_FLOAT_COMPARE_LESS_EQUAL = 1, NODE_FLOAT_COMPARE_GREATER_THAN = 2, NODE_FLOAT_COMPARE_GREATER_EQUAL = 3, NODE_FLOAT_COMPARE_EQUAL = 4, NODE_FLOAT_COMPARE_NOT_EQUAL = 5, -}; +} FloatCompareOperation; /* Clamp node types. */ enum { @@ -1459,10 +1511,23 @@ typedef enum GeometryNodeTriangulateQuads { GEO_NODE_TRIANGULATE_QUAD_SHORTEDGE = 3, } GeometryNodeTriangulateQuads; -typedef enum GeometryNodeUseAttributeFlag { - GEO_NODE_USE_ATTRIBUTE_A = (1 << 0), - GEO_NODE_USE_ATTRIBUTE_B = (1 << 1), -} GeometryNodeUseAttributeFlag; +typedef enum GeometryNodePointInstanceType { + GEO_NODE_POINT_INSTANCE_TYPE_OBJECT = 0, + GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION = 1, +} GeometryNodePointInstanceType; + +typedef enum GeometryNodeAttributeInputMode { + GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE = 0, + GEO_NODE_ATTRIBUTE_INPUT_FLOAT = 1, + GEO_NODE_ATTRIBUTE_INPUT_VECTOR = 2, + GEO_NODE_ATTRIBUTE_INPUT_COLOR = 3, + GEO_NODE_ATTRIBUTE_INPUT_BOOLEAN = 4, +} GeometryNodeAttributeInputMode; + +typedef enum GeometryNodePointDistributeMethod { + GEO_NODE_POINT_DISTRIBUTE_RANDOM = 0, + GEO_NODE_POINT_DISTRIBUTE_POISSON = 1, +} GeometryNodePointDistributeMethod; #ifdef __cplusplus } diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index 71f67d8a3b4..8b13db8a012 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -38,9 +38,8 @@ extern "C" { struct AnimData; struct BoundBox; -struct DerivedMesh; struct FluidsimSettings; -struct GpencilBatchCache; +struct GeometrySet; struct Ipo; struct Material; struct Mesh; @@ -51,7 +50,6 @@ struct RigidBodyOb; struct SculptSession; struct SoftBody; struct bGPdata; -struct GeometrySet; /* Vertex Groups - Name Info */ typedef struct bDeformGroup { @@ -150,14 +148,17 @@ typedef struct Object_Runtime { */ struct ID *data_orig; /** - * Object data structure created during object evaluation. - * It has all modifiers applied. + * Object data structure created during object evaluation. It has all modifiers applied. + * The type is determined by the type of the original object. For example, for mesh and curve + * objects, this is a mesh. For a volume object, this is a volume. */ struct ID *data_eval; /** - * Some objects support evaluating to a geometry set instead of a single ID. In those cases the - * evaluated geometry will be stored here instead of in #data_eval. + * Objects can evaluate to a geometry set instead of a single ID. In those cases, the evaluated + * geometry set will be stored here. An ID of the correct type is still stored in #data_eval. + * #geometry_set_eval might reference the ID pointed to by #data_eval as well, but does not own + * the data. */ struct GeometrySet *geometry_set_eval; diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 2f83c57bc82..bfa52dd6a29 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -33,15 +33,10 @@ #define USE_SETSCENE_CHECK #include "DNA_ID.h" -#include "DNA_collection_types.h" -#include "DNA_color_types.h" /* color management */ -#include "DNA_curveprofile_types.h" +#include "DNA_color_types.h" /* color management */ #include "DNA_customdata_types.h" /* Scene's runtime cddata masks. */ -#include "DNA_freestyle_types.h" #include "DNA_layer_types.h" #include "DNA_listBase.h" -#include "DNA_material_types.h" -#include "DNA_userdef_types.h" #include "DNA_vec_types.h" #include "DNA_view3d_types.h" @@ -323,8 +318,7 @@ typedef enum eScenePassType { #define RE_PASSNAME_FREESTYLE "Freestyle" #define RE_PASSNAME_BLOOM "BloomCol" -#define RE_PASSNAME_VOLUME_TRANSMITTANCE "VolumeTransmCol" -#define RE_PASSNAME_VOLUME_SCATTER "VolumeScatterCol" +#define RE_PASSNAME_VOLUME_LIGHT "VolumeDir" /* View - MultiView */ typedef struct SceneRenderView { @@ -1345,6 +1339,18 @@ typedef struct MeshStatVis { float sharp_min, sharp_max; } MeshStatVis; +typedef struct SequencerToolSettings { + /* eSeqImageFitMethod */ + int fit_method; +} SequencerToolSettings; + +typedef enum eSeqImageFitMethod { + SEQ_SCALE_TO_FIT, + SEQ_SCALE_TO_FILL, + SEQ_STRETCH_TO_FILL, + SEQ_USE_ORIGINAL_SIZE, +} eSeqImageFitMethod; + /* *************************************************************** */ /* Tool Settings */ @@ -1519,6 +1525,9 @@ typedef struct ToolSettings { * Temporary until there is a proper preset system that stores the profiles or maybe stores * entire bevel configurations. */ struct CurveProfile *custom_bevel_profile_preset; + + struct SequencerToolSettings *sequencer_tool_settings; + } ToolSettings; /* *************************************************************** */ @@ -1783,7 +1792,7 @@ typedef struct Scene { ListBase view_layers; /* Not an actual datablock, but memory owned by scene. */ - Collection *master_collection; + struct Collection *master_collection; struct SceneCollection *collection DNA_DEPRECATED; /** Settings to be override by workspaces. */ diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h index e21f3e1e706..ef14a5c52d4 100644 --- a/source/blender/makesdna/DNA_sequence_types.h +++ b/source/blender/makesdna/DNA_sequence_types.h @@ -33,9 +33,8 @@ #include "DNA_color_types.h" #include "DNA_defs.h" #include "DNA_listBase.h" -#include "DNA_session_uuid_types.h" -#include "DNA_vec_types.h" -#include "DNA_vfont_types.h" +#include "DNA_session_uuid_types.h" /* for #SessionUUID */ +#include "DNA_vec_types.h" /* for #rctf */ #ifdef __cplusplus extern "C" { @@ -44,6 +43,7 @@ extern "C" { struct Ipo; struct MovieClip; struct Scene; +struct VFont; struct bSound; /* strlens; 256= FILE_MAXFILE, 768= FILE_MAXDIR */ @@ -278,12 +278,12 @@ typedef struct Editing { struct SeqCache *cache; /* Cache control */ - float recycle_max_cost; + float recycle_max_cost; /* UNUSED only for versioning. */ int cache_flag; struct PrefetchJob *prefetch_job; - /* Must be initialized only by BKE_sequencer_cache_create() */ + /* Must be initialized only by seq_cache_create() */ int64_t disk_cache_timestamp; } Editing; @@ -338,7 +338,7 @@ typedef struct GaussianBlurVars { typedef struct TextVars { char text[512]; - VFont *text_font; + struct VFont *text_font; int text_blf_id; int text_size; float color[4], shadow_color[4], box_color[4]; diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index a554caccc4e..4276e8b568e 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -621,6 +621,10 @@ typedef enum eSpaceSeq_Flag { SEQ_SHOW_METADATA = (1 << 10), SEQ_SHOW_MARKERS = (1 << 11), /* show markers region */ SEQ_ZOOM_TO_FIT = (1 << 12), + SEQ_SHOW_STRIP_OVERLAY = (1 << 13), + SEQ_SHOW_STRIP_NAME = (1 << 14), + SEQ_SHOW_STRIP_SOURCE = (1 << 15), + SEQ_SHOW_STRIP_DURATION = (1 << 16), } eSpaceSeq_Flag; /* SpaceSeq.view */ @@ -664,6 +668,24 @@ typedef enum eSpaceSeq_OverlayType { /** \name File Selector * \{ */ +/** + * Information to identify a asset library. May be either one of the predefined types (current + * 'Main', builtin library, project library), or a custom type as defined in the Preferences. + * + * If the type is set to #FILE_ASSET_LIBRARY_CUSTOM, idname must have the name to identify the + * custom library. Otherwise idname is not used. + */ +typedef struct FileSelectAssetLibraryUID { + short type; + char _pad[2]; + /** + * If showing a custom asset library (#FILE_ASSET_LIBRARY_CUSTOM), this is the index of the + * #bUserAssetLibrary within #UserDef.asset_libraries. + * Should be ignored otherwise (but better set to -1 then, for sanity and debugging). + */ + int custom_library_index; +} FileSelectAssetLibraryUID; + /* Config and Input for File Selector */ typedef struct FileSelectParams { /** Title, also used for the text of the execute button. */ @@ -698,7 +720,7 @@ typedef struct FileSelectParams { /* short */ /** XXXXX for now store type here, should be moved to the operator. */ - short type; + short type; /* eFileSelectType */ /** Settings for filter, hiding dots files. */ short flag; /** Sort order. */ @@ -708,6 +730,7 @@ typedef struct FileSelectParams { /** Details toggles (file size, creation date, etc.) */ char details_flags; char _pad2[3]; + /** Filter when (flags & FILE_FILTER) is true. */ int filter; @@ -723,6 +746,32 @@ typedef struct FileSelectParams { /* XXX --- end unused -- */ } FileSelectParams; +/** + * File selection parameters for asset browsing mode, with #FileSelectParams as base. + */ +typedef struct FileAssetSelectParams { + FileSelectParams base_params; + + FileSelectAssetLibraryUID asset_library; +} FileAssetSelectParams; + +/** + * A wrapper to store previous and next folder lists (#FolderList) for a specific browse mode + * (#eFileBrowse_Mode). + */ +typedef struct FileFolderHistory { + struct FileFolderLists *next, *prev; + + /** The browse mode this prev/next folder-lists are created for. */ + char browse_mode; /* eFileBrowse_Mode */ + char _pad[7]; + + /** Holds the list of previous directories to show. */ + ListBase folders_prev; + /** Holds the list of next directories (pushed from previous) to show. */ + ListBase folders_next; +} FileFolderHistory; + /* File Browser */ typedef struct SpaceFile { SpaceLink *next, *prev; @@ -733,20 +782,42 @@ typedef struct SpaceFile { char _pad0[6]; /* End 'SpaceLink' header. */ - char _pad1[4]; + /** Is this a File Browser or an Asset Browser? */ + char browse_mode; /* eFileBrowse_Mode */ + char _pad1[1]; + + short tags; + int scroll_offset; - /** Config and input for file select. */ - struct FileSelectParams *params; + /** Config and input for file select. One for each browse-mode, to keep them independent. */ + FileSelectParams *params; + FileAssetSelectParams *asset_params; + + void *_pad2; - /** Holds the list of files to show. */ + /** + * Holds the list of files to show. + * Currently recreated when browse-mode changes. Could be per browse-mode to avoid refreshes. + */ struct FileList *files; - /** Holds the list of previous directories to show. */ + /** + * Holds the list of previous directories to show. Owned by `folder_histories` below. + */ ListBase *folders_prev; - /** Holds the list of next directories (pushed from previous) to show. */ + /** + * Holds the list of next directories (pushed from previous) to show. Owned by + * `folder_histories` below. + */ ListBase *folders_next; + /** + * This actually owns the prev/next folder-lists above. On browse-mode change, the lists of the + * new mode get assigned to the above. + */ + ListBase folder_histories; /* FileFolderHistory */ + /* operator that is invoking fileselect * op->exec() will be called on the 'Load' button. * if operator provides op->cancel(), then this will be invoked @@ -763,6 +834,30 @@ typedef struct SpaceFile { short systemnr, system_bookmarknr; } SpaceFile; +/* SpaceFile.browse_mode (File Space Browsing Mode) */ +typedef enum eFileBrowse_Mode { + /* Regular Blender File Browser */ + FILE_BROWSE_MODE_FILES = 0, + /* Asset Browser */ + FILE_BROWSE_MODE_ASSETS = 1, +} eFileBrowse_Mode; + +typedef enum eFileAssetLibrary_Type { + /* For the future. Display assets bundled with Blender by default. */ + // FILE_ASSET_LIBRARY_BUNDLED = 0, + /** Display assets from the current session (current "Main"). */ + FILE_ASSET_LIBRARY_LOCAL = 1, + /* For the future. Display assets for the current project. */ + // FILE_ASSET_LIBRARY_PROJECT = 2, + + /** Display assets from custom asset libraries, as defined in the preferences + * (#bUserAssetLibrary). The name will be taken from #FileSelectParams.asset_library.idname + * then. + * In RNA, we add the index of the custom library to this to identify it by index. So keep + * this last! */ + FILE_ASSET_LIBRARY_CUSTOM = 100, +} eFileAssetLibrary_Type; + /* FileSelectParams.display */ enum eFileDisplayType { /** Internal (not exposed to users): Keep whatever display type was used during the last File @@ -792,6 +887,13 @@ enum eFileSortType { FILE_SORT_SIZE = 4, }; +/* SpaceFile.tags */ +enum eFileTags { + /** Tag the space as having to update files representing or containing main data. Must be set + * after file read and undo/redo. */ + FILE_TAG_REBUILD_MAIN_FILES = (1 << 0), +}; + /* FileSelectParams.details_flags */ enum eFileDetails { FILE_DETAILS_SIZE = (1 << 0), @@ -807,12 +909,15 @@ enum eFileDetails { #define FILE_MAX_LIBEXTRA (FILE_MAX + MAX_ID_NAME) /* filesel types */ -#define FILE_UNIX 8 -#define FILE_BLENDER 8 /* don't display relative paths */ -#define FILE_SPECIAL 9 +typedef enum eFileSelectType { + FILE_LOADLIB = 1, + FILE_MAIN = 2, + FILE_MAIN_ASSET = 3, -#define FILE_LOADLIB 1 -#define FILE_MAIN 2 + FILE_UNIX = 8, + FILE_BLENDER = 8, /* don't display relative paths */ + FILE_SPECIAL = 9, +} eFileSelectType; /* filesel op property -> action */ typedef enum eFileSel_Action { @@ -840,6 +945,7 @@ typedef enum eFileSel_Params_Flag { FILE_SORT_INVERT = (1 << 11), FILE_HIDE_TOOL_PROPS = (1 << 12), FILE_CHECK_EXISTING = (1 << 13), + FILE_ASSETS_ONLY = (1 << 14), } eFileSel_Params_Flag; /* sfile->params->rename_flag */ @@ -883,6 +989,7 @@ typedef enum eFileSel_File_Types { FILE_TYPE_USD = (1 << 18), FILE_TYPE_VOLUME = (1 << 19), + FILE_TYPE_ASSET = (1 << 28), /** An FS directory (i.e. S_ISDIR on its path is true). */ FILE_TYPE_DIR = (1 << 30), FILE_TYPE_BLENDERLIB = (1u << 31), @@ -983,9 +1090,16 @@ typedef struct FileDirEntry { /** Optional argument for shortcuts, aliases etc. */ char *redirection_path; - /** TODO: make this a real ID pointer? */ - void *poin; - struct ImBuf *image; + /** When showing local IDs (FILE_MAIN, FILE_MAIN_ASSET), ID this file represents. Note comment + * for FileListInternEntry.local_data, the same applies here! */ + ID *id; + /** If this file represents an asset, its asset data is here. Note that we may show assets of + * external files in which case this is set but not the id above. + * Note comment for FileListInternEntry.local_data, the same applies here! */ + struct AssetMetaData *asset_data; + + /* The icon_id for the preview image. */ + int preview_icon_id; /* Tags are for info only, most of filtering is done in asset engine. */ char **tags; diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index f5ac6ca4496..d9ee9a27294 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -375,7 +375,7 @@ typedef struct ThemeSpace { /** Two uses, for uvs with modifier applied on mesh and uvs during painting. */ unsigned char uv_shadow[4]; - /** Outliner - filter match. */ + /** Search filter match, used for property search and in the outliner. */ unsigned char match[4]; /** Outliner - selected item. */ unsigned char selected_highlight[4]; @@ -569,6 +569,13 @@ enum { USER_MENU_TYPE_PROP = 4, }; +typedef struct bUserAssetLibrary { + struct bUserAssetLibrary *next, *prev; + + char name[64]; /* MAX_NAME */ + char path[1024]; /* FILE_MAX */ +} bUserAssetLibrary; + typedef struct SolidLight { int flag; float smooth; @@ -632,10 +639,12 @@ typedef struct UserDef_Experimental { /* The following options are automatically sanitized (set to 0) * when the release cycle is not alpha. */ char use_new_hair_type; + char use_new_point_cloud_type; char use_sculpt_vertex_colors; char use_switch_object_operator; char use_sculpt_tools_tilt; char use_object_add_tool; + char _pad[7]; /** `makesdna` does not allow empty structs. */ } UserDef_Experimental; @@ -681,8 +690,7 @@ typedef struct UserDef { short versions; short dbl_click_time; - char _pad0[2]; - char wheellinescroll; + char _pad0[3]; char mini_axis_type; /** #eUserpref_UI_Flag. */ int uiflag; @@ -739,6 +747,8 @@ typedef struct UserDef { struct ListBase autoexec_paths; /** #bUserMenu. */ struct ListBase user_menus; + /** #bUserAssetLibrary */ + struct ListBase asset_libraries; char keyconfigstr[64]; diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h index a7ad18d7cf3..f07af2c14a0 100644 --- a/source/blender/makesdna/DNA_windowmanager_types.h +++ b/source/blender/makesdna/DNA_windowmanager_types.h @@ -24,10 +24,8 @@ #pragma once #include "DNA_listBase.h" -#include "DNA_screen_types.h" -#include "DNA_userdef_types.h" -#include "DNA_vec_types.h" -#include "DNA_xr_types.h" +#include "DNA_screen_types.h" /* for #ScrAreaMap */ +#include "DNA_xr_types.h" /* for #XrSessionSettings */ #include "DNA_ID.h" diff --git a/source/blender/makesdna/DNA_workspace_types.h b/source/blender/makesdna/DNA_workspace_types.h index edca887639e..c5c2351c718 100644 --- a/source/blender/makesdna/DNA_workspace_types.h +++ b/source/blender/makesdna/DNA_workspace_types.h @@ -22,7 +22,7 @@ #pragma once -#include "DNA_scene_types.h" +#include "DNA_ID.h" #ifdef __cplusplus extern "C" { diff --git a/source/blender/makesdna/intern/CMakeLists.txt b/source/blender/makesdna/intern/CMakeLists.txt index 2051335dd7e..a7adaa7e258 100644 --- a/source/blender/makesdna/intern/CMakeLists.txt +++ b/source/blender/makesdna/intern/CMakeLists.txt @@ -138,6 +138,7 @@ set(SRC ../../blenlib/intern/hash_mm2a.c ../../blenlib/intern/listbase.c + ../DNA_asset_defaults.h ../DNA_brush_defaults.h ../DNA_cachefile_defaults.h ../DNA_camera_defaults.h diff --git a/source/blender/makesdna/intern/dna_defaults.c b/source/blender/makesdna/intern/dna_defaults.c index 1a8bd25215f..3e4d5d87fb0 100644 --- a/source/blender/makesdna/intern/dna_defaults.c +++ b/source/blender/makesdna/intern/dna_defaults.c @@ -85,6 +85,7 @@ #include "DNA_defaults.h" #include "DNA_armature_types.h" +#include "DNA_asset_types.h" #include "DNA_brush_types.h" #include "DNA_cachefile_types.h" #include "DNA_camera_types.h" @@ -117,6 +118,7 @@ #include "DNA_world_types.h" #include "DNA_armature_defaults.h" +#include "DNA_asset_defaults.h" #include "DNA_brush_defaults.h" #include "DNA_cachefile_defaults.h" #include "DNA_camera_defaults.h" @@ -148,6 +150,9 @@ #define SDNA_DEFAULT_DECL_STRUCT(struct_name) \ static const struct_name DNA_DEFAULT_##struct_name = _DNA_DEFAULT_##struct_name +/* DNA_asset_defaults.h */ +SDNA_DEFAULT_DECL_STRUCT(AssetMetaData); + /* DNA_armature_defaults.h */ SDNA_DEFAULT_DECL_STRUCT(bArmature); @@ -338,7 +343,10 @@ extern const bTheme U_theme_default; /** Keep headers sorted. */ const void *DNA_default_table[SDNA_TYPE_MAX] = { - /* DNA_arnature_defaults.h */ + /* DNA_asset_defaults.h */ + SDNA_DEFAULT_DECL(AssetMetaData), + + /* DNA_armature_defaults.h */ SDNA_DEFAULT_DECL(bArmature), /* DNA_brush_defaults.h */ diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c index 81a7da7b4d8..54d2bc88d16 100644 --- a/source/blender/makesdna/intern/makesdna.c +++ b/source/blender/makesdna/intern/makesdna.c @@ -139,6 +139,7 @@ static const char *includefiles[] = { "DNA_volume_types.h", "DNA_simulation_types.h", "DNA_pointcache_types.h", + "DNA_asset_types.h", /* see comment above before editing! */ @@ -1533,6 +1534,7 @@ int main(int argc, char **argv) #include "DNA_action_types.h" #include "DNA_anim_types.h" #include "DNA_armature_types.h" +#include "DNA_asset_types.h" #include "DNA_boid_types.h" #include "DNA_brush_types.h" #include "DNA_cachefile_types.h" diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index a581edcb04b..2d2e8d1a686 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -70,6 +70,8 @@ extern StructRNA RNA_ArrayGpencilModifier; extern StructRNA RNA_ArrayModifier; extern StructRNA RNA_Attribute; extern StructRNA RNA_AttributeGroup; +extern StructRNA RNA_AssetMetaData; +extern StructRNA RNA_AssetTag; extern StructRNA RNA_BackgroundImage; extern StructRNA RNA_BevelModifier; extern StructRNA RNA_BezierSplinePoint; @@ -147,6 +149,7 @@ extern StructRNA RNA_CompositorNodeDilateErode; extern StructRNA RNA_CompositorNodeDisplace; extern StructRNA RNA_CompositorNodeDistanceMatte; extern StructRNA RNA_CompositorNodeDoubleEdgeMask; +extern StructRNA RNA_CompositorNodeExposure; extern StructRNA RNA_CompositorNodeFilter; extern StructRNA RNA_CompositorNodeFlip; extern StructRNA RNA_CompositorNodeGamma; @@ -202,6 +205,7 @@ extern StructRNA RNA_CopyRotationConstraint; extern StructRNA RNA_CopyScaleConstraint; extern StructRNA RNA_CopyTransformsConstraint; extern StructRNA RNA_CorrectiveSmoothModifier; +extern StructRNA RNA_CryptomatteEntry; extern StructRNA RNA_Curve; extern StructRNA RNA_CurveMap; extern StructRNA RNA_CurveMapPoint; @@ -250,7 +254,9 @@ extern StructRNA RNA_FModifierPython; extern StructRNA RNA_FModifierStepped; extern StructRNA RNA_FaceMap; extern StructRNA RNA_FieldSettings; +extern StructRNA RNA_FileAssetSelectParams; extern StructRNA RNA_FileBrowserFSMenuEntry; +extern StructRNA RNA_FileSelectEntry; extern StructRNA RNA_FileSelectParams; extern StructRNA RNA_FloatAttribute; extern StructRNA RNA_FloatAttributeValue; @@ -694,6 +700,7 @@ extern StructRNA RNA_UVProjector; extern StructRNA RNA_UVWarpModifier; extern StructRNA RNA_UnitSettings; extern StructRNA RNA_UnknownType; +extern StructRNA RNA_UserAssetLibrary; extern StructRNA RNA_UserSolidLight; extern StructRNA RNA_VertexcolorGpencilModifier; extern StructRNA RNA_VectorFont; diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h index a94466e30c2..69bd6142cad 100644 --- a/source/blender/makesrna/RNA_enum_types.h +++ b/source/blender/makesrna/RNA_enum_types.h @@ -56,6 +56,7 @@ extern const EnumPropertyItem rna_enum_mesh_select_mode_items[]; extern const EnumPropertyItem rna_enum_mesh_select_mode_uv_items[]; extern const EnumPropertyItem rna_enum_mesh_delimit_mode_items[]; extern const EnumPropertyItem rna_enum_space_graph_mode_items[]; +extern const EnumPropertyItem rna_enum_space_file_browse_mode_items[]; extern const EnumPropertyItem rna_enum_space_sequencer_view_type_items[]; extern const EnumPropertyItem rna_enum_space_type_items[]; extern const EnumPropertyItem rna_enum_space_image_mode_items[]; diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index 9aea5b26a54..3db8909c8a7 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -31,6 +31,7 @@ set(DEFSRC rna_animviz.c rna_armature.c rna_attribute.c + rna_asset.c rna_boid.c rna_brush.c rna_cachefile.c @@ -99,6 +100,7 @@ set(DEFSRC if(WITH_EXPERIMENTAL_FEATURES) add_definitions(-DWITH_GEOMETRY_NODES) + add_definitions(-DWITH_POINT_CLOUD) add_definitions(-DWITH_HAIR_NODES) list(APPEND DEFSRC rna_hair.c @@ -426,6 +428,7 @@ set(LIB bf_editor_animation bf_editor_armature + bf_editor_asset bf_editor_curve bf_editor_gizmo_library bf_editor_gpencil diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 9eed1fcf085..c2c95c59002 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -4270,6 +4270,7 @@ static RNAProcessItem PROCESS_ITEMS[] = { {"rna_animviz.c", NULL, RNA_def_animviz}, {"rna_armature.c", "rna_armature_api.c", RNA_def_armature}, {"rna_attribute.c", NULL, RNA_def_attribute}, + {"rna_asset.c", NULL, RNA_def_asset}, {"rna_boid.c", NULL, RNA_def_boid}, {"rna_brush.c", NULL, RNA_def_brush}, {"rna_cachefile.c", NULL, RNA_def_cachefile}, @@ -4308,7 +4309,9 @@ static RNAProcessItem PROCESS_ITEMS[] = { {"rna_packedfile.c", NULL, RNA_def_packedfile}, {"rna_palette.c", NULL, RNA_def_palette}, {"rna_particle.c", NULL, RNA_def_particle}, +#ifdef WITH_POINT_CLOUD {"rna_pointcloud.c", NULL, RNA_def_pointcloud}, +#endif {"rna_pose.c", "rna_pose_api.c", RNA_def_pose}, {"rna_curveprofile.c", NULL, RNA_def_profile}, {"rna_lightprobe.c", NULL, RNA_def_lightprobe}, diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index cb316e56a68..7c67bfc360b 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -289,9 +289,11 @@ short RNA_type_to_ID_code(const StructRNA *type) if (base_type == &RNA_PaintCurve) { return ID_PC; } +# ifdef WITH_POINT_CLOUD if (base_type == &RNA_PointCloud) { return ID_PT; } +# endif if (base_type == &RNA_LightProbe) { return ID_LP; } @@ -397,7 +399,11 @@ StructRNA *ID_code_to_RNA_type(short idcode) case ID_PC: return &RNA_PaintCurve; case ID_PT: +# ifdef WITH_POINT_CLOUD return &RNA_PointCloud; +# else + return &RNA_ID; +# endif case ID_LP: return &RNA_LightProbe; case ID_SCE: @@ -1188,7 +1194,7 @@ static void rna_def_image_preview(BlenderRNA *brna) prop = RNA_def_property(srna, "image_pixels", PROP_INT, PROP_NONE); RNA_def_property_flag(prop, PROP_DYNAMIC); RNA_def_property_multi_array(prop, 1, NULL); - RNA_def_property_ui_text(prop, "Image Pixels", "Image pixels, as bytes (always RGBA 32bits)"); + RNA_def_property_ui_text(prop, "Image Pixels", "Image pixels, as bytes (always 32-bit RGBA)"); RNA_def_property_dynamic_array_funcs(prop, "rna_ImagePreview_image_pixels_get_length"); RNA_def_property_int_funcs( prop, "rna_ImagePreview_image_pixels_get", "rna_ImagePreview_image_pixels_set", NULL); @@ -1221,7 +1227,7 @@ static void rna_def_image_preview(BlenderRNA *brna) prop = RNA_def_property(srna, "icon_pixels", PROP_INT, PROP_NONE); RNA_def_property_flag(prop, PROP_DYNAMIC); RNA_def_property_multi_array(prop, 1, NULL); - RNA_def_property_ui_text(prop, "Icon Pixels", "Icon pixels, as bytes (always RGBA 32bits)"); + RNA_def_property_ui_text(prop, "Icon Pixels", "Icon pixels, as bytes (always 32-bit RGBA)"); RNA_def_property_dynamic_array_funcs(prop, "rna_ImagePreview_icon_pixels_get_length"); RNA_def_property_int_funcs( prop, "rna_ImagePreview_icon_pixels_get", "rna_ImagePreview_icon_pixels_set", NULL); @@ -1522,6 +1528,11 @@ static void rna_def_ID(BlenderRNA *brna) RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON); RNA_def_property_ui_text(prop, "Library", "Library file the data-block is linked from"); + prop = RNA_def_property(srna, "asset_data", PROP_POINTER, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON); + RNA_def_property_ui_text(prop, "Asset Data", "Additional data for an asset data-block"); + prop = RNA_def_pointer( srna, "override_library", "IDOverrideLibrary", "Library Override", "Library override data"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 4991f34c3f6..4262d5590c8 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -31,6 +31,7 @@ #include "DNA_scene_types.h" #include "DNA_windowmanager_types.h" +#include "BLI_alloca.h" #include "BLI_blenlib.h" #include "BLI_dynstr.h" #include "BLI_ghash.h" @@ -1104,8 +1105,11 @@ bool RNA_struct_bl_idname_ok_or_report(ReportList *reports, const bool failure = false; #endif if (p == NULL || p == identifier || p + len_sep >= identifier + len_id) { - BKE_reportf( - reports, report_level, "'%s' doesn't contain '%s' with prefix & suffix", identifier, sep); + BKE_reportf(reports, + report_level, + "'%s' does not contain '%s' with prefix and suffix", + identifier, + sep); return failure; } @@ -4957,14 +4961,10 @@ PointerRNA rna_array_lookup_int( static char *rna_path_token(const char **path, char *fixedbuf, int fixedlen, int bracket) { const char *p; - char *buf; - char quote = '\0'; - int i, j, len, escape; - - len = 0; + int len = 0; if (bracket) { - /* get data between [], check escaping ] with \] */ + /* get data between [], check escaping quotes and back-slashes with #BLI_str_unescape. */ if (**path == '[') { (*path)++; } @@ -4974,33 +4974,24 @@ static char *rna_path_token(const char **path, char *fixedbuf, int fixedlen, int p = *path; - /* 2 kinds of lookups now, quoted or unquoted */ - quote = *p; - - if (quote != '"') { /* " - this comment is hack for Aligorith's text editor's sanity */ - quote = 0; - } - - if (quote == 0) { + /* 2 kinds of look-ups now, quoted or unquoted. */ + if (*p != '"') { while (*p && (*p != ']')) { len++; p++; } } else { - escape = 0; - /* skip the first quote */ - len++; - p++; - while (*p && (*p != quote || escape)) { - escape = (*p == '\\'); - len++; - p++; + const char *p_end = BLI_str_escape_find_quote(p + 1); + if (p_end == NULL) { + /* No Matching quote. */ + return NULL; } + /* Skip the last quoted char to get the `]`. */ + p_end += 1; - /* skip the last quoted char to get the ']' */ - len++; - p++; + len += (p_end - p); + p = p_end; } if (*p != ']') { @@ -5022,25 +5013,13 @@ static char *rna_path_token(const char **path, char *fixedbuf, int fixedlen, int return NULL; } - /* try to use fixed buffer if possible */ - if (len + 1 < fixedlen) { - buf = fixedbuf; - } - else { - buf = MEM_mallocN(sizeof(char) * (len + 1), "rna_path_token"); - } + /* Try to use fixed buffer if possible. */ + char *buf = (len + 1 < fixedlen) ? fixedbuf : MEM_mallocN(sizeof(char) * (len + 1), __func__); /* copy string, taking into account escaped ] */ if (bracket) { - for (p = *path, i = 0, j = 0; i < len; i++, p++) { - if (*p == '\\' && *(p + 1) == quote) { - } - else { - buf[j++] = *p; - } - } - - buf[j] = 0; + BLI_str_unescape(buf, *path, len); + p = (*path) + len; } else { memcpy(buf, *path, sizeof(char) * len); @@ -5552,8 +5531,7 @@ char *RNA_path_append( const char *path, PointerRNA *UNUSED(ptr), PropertyRNA *prop, int intkey, const char *strkey) { DynStr *dynstr; - const char *s; - char appendstr[128], *result; + char *result; dynstr = BLI_dynstr_new(); @@ -5572,22 +5550,15 @@ char *RNA_path_append( BLI_dynstr_append(dynstr, "["); if (strkey) { + const int strkey_esc_max_size = (strlen(strkey) * 2) + 1; + char *strkey_esc = BLI_array_alloca(strkey_esc, strkey_esc_max_size); + BLI_str_escape(strkey_esc, strkey, strkey_esc_max_size); BLI_dynstr_append(dynstr, "\""); - for (s = strkey; *s; s++) { - if (*s == '[') { - appendstr[0] = '\\'; - appendstr[1] = *s; - appendstr[2] = 0; - } - else { - appendstr[0] = *s; - appendstr[1] = 0; - } - BLI_dynstr_append(dynstr, appendstr); - } + BLI_dynstr_append(dynstr, strkey_esc); BLI_dynstr_append(dynstr, "\""); } else { + char appendstr[128]; BLI_snprintf(appendstr, sizeof(appendstr), "%d", intkey); BLI_dynstr_append(dynstr, appendstr); } @@ -5837,7 +5808,7 @@ ID *RNA_find_real_ID_and_path(Main *bmain, ID *id, const char **r_path) if (r_path) { *r_path = "collection"; } - return (ID *)BKE_collection_master_scene_search(bmain, (Collection *)id); + return (ID *)BKE_collection_master_scene_search(bmain, (struct Collection *)id); default: return NULL; @@ -6008,7 +5979,7 @@ char *RNA_path_from_ID_to_property_index(PointerRNA *ptr, } else { char propname_esc[MAX_IDPROP_NAME * 2]; - BLI_strescape(propname_esc, propname, sizeof(propname_esc)); + BLI_str_escape(propname_esc, propname, sizeof(propname_esc)); path = BLI_sprintfN("%s[\"%s\"]%s", ptrpath, propname_esc, index_str); } MEM_freeN(ptrpath); @@ -6019,7 +5990,7 @@ char *RNA_path_from_ID_to_property_index(PointerRNA *ptr, } else { char propname_esc[MAX_IDPROP_NAME * 2]; - BLI_strescape(propname_esc, propname, sizeof(propname_esc)); + BLI_str_escape(propname_esc, propname, sizeof(propname_esc)); path = BLI_sprintfN("[\"%s\"]%s", propname_esc, index_str); } } @@ -6105,7 +6076,7 @@ char *RNA_path_full_ID_py(Main *bmain, ID *id) char id_esc[(sizeof(id->name) - 2) * 2]; - BLI_strescape(id_esc, id->name + 2, sizeof(id_esc)); + BLI_str_escape(id_esc, id->name + 2, sizeof(id_esc)); return BLI_sprintfN("bpy.data.%s[\"%s\"]%s%s", BKE_idtype_idcode_to_name_plural(GS(id->name)), @@ -7059,7 +7030,7 @@ char *RNA_property_as_string( buf = MEM_mallocN(sizeof(char) * (length + 1), "RNA_property_as_string"); buf_esc = MEM_mallocN(sizeof(char) * (length * 2 + 1), "RNA_property_as_string esc"); RNA_property_string_get(ptr, prop, buf); - BLI_strescape(buf_esc, buf, length * 2 + 1); + BLI_str_escape(buf_esc, buf, length * 2 + 1); MEM_freeN(buf); BLI_dynstr_appendf(dynstr, "\"%s\"", buf_esc); MEM_freeN(buf_esc); diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c index 2bf4de7af60..c0b2de268cd 100644 --- a/source/blender/makesrna/intern/rna_access_compare_override.c +++ b/source/blender/makesrna/intern/rna_access_compare_override.c @@ -23,6 +23,7 @@ #include "MEM_guardedalloc.h" #include "DNA_ID.h" +#include "DNA_anim_types.h" #include "DNA_constraint_types.h" #include "DNA_gpencil_modifier_types.h" #include "DNA_key_types.h" @@ -84,6 +85,12 @@ bool RNA_property_overridable_get(PointerRNA *ptr, PropertyRNA *prop) return true; } } + else if (RNA_struct_is_a(ptr->type, &RNA_NlaTrack)) { + NlaTrack *nla_track = ptr->data; + if (nla_track->flag & NLATRACK_OVERRIDELIBRARY_LOCAL) { + return true; + } + } /* If this is a RNA-defined property (real or 'virtual' IDProp), * we want to use RNA prop flag. */ return !(prop->flag_override & PROPOVERRIDE_NO_COMPARISON) && diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c index 0a9f2ff4819..10f86fe2671 100644 --- a/source/blender/makesrna/intern/rna_animation.c +++ b/source/blender/makesrna/intern/rna_animation.c @@ -587,7 +587,7 @@ static void rna_KeyingSet_paths_clear(KeyingSet *keyingset, ReportList *reports) /* needs wrapper function to push notifier */ static NlaTrack *rna_NlaTrack_new(ID *id, AnimData *adt, Main *bmain, bContext *C, NlaTrack *track) { - NlaTrack *new_track = BKE_nlatrack_add(adt, track); + NlaTrack *new_track = BKE_nlatrack_add(adt, track, ID_IS_OVERRIDE_LIBRARY(id)); WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_ADDED, NULL); @@ -732,6 +732,60 @@ bool rna_AnimaData_override_apply(Main *UNUSED(bmain), return false; } +bool rna_NLA_tracks_override_apply(Main *bmain, + PointerRNA *ptr_dst, + PointerRNA *ptr_src, + PointerRNA *UNUSED(ptr_storage), + PropertyRNA *UNUSED(prop_dst), + PropertyRNA *UNUSED(prop_src), + PropertyRNA *UNUSED(prop_storage), + const int UNUSED(len_dst), + const int UNUSED(len_src), + const int UNUSED(len_storage), + PointerRNA *UNUSED(ptr_item_dst), + PointerRNA *UNUSED(ptr_item_src), + PointerRNA *UNUSED(ptr_item_storage), + IDOverrideLibraryPropertyOperation *opop) +{ + BLI_assert(opop->operation == IDOVERRIDE_LIBRARY_OP_INSERT_AFTER && + "Unsupported RNA override operation on constraints collection"); + + AnimData *anim_data_dst = (AnimData *)ptr_dst->data; + AnimData *anim_data_src = (AnimData *)ptr_src->data; + + /* Remember that insertion operations are defined and stored in correct order, which means that + * even if we insert several items in a row, we always insert first one, then second one, etc. + * So we should always find 'anchor' track in both _src *and* _dst. */ + NlaTrack *nla_track_anchor = NULL; +# if 0 + /* This is not working so well with index-based insertion, especially in case some tracks get + * added to lib linked data. So we simply add locale tracks at the end of the list always, order + * of override operations should ensure order of local tracks is preserved properly. */ + if (opop->subitem_local_index >= 0) { + nla_track_anchor = BLI_findlink(&anim_data_dst->nla_tracks, opop->subitem_local_index); + } + /* Otherwise we just insert in first position. */ +# else + nla_track_anchor = anim_data_dst->nla_tracks.last; +# endif + + NlaTrack *nla_track_src = NULL; + if (opop->subitem_local_index >= 0) { + nla_track_src = BLI_findlink(&anim_data_src->nla_tracks, opop->subitem_local_index); + } + nla_track_src = nla_track_src ? nla_track_src->next : anim_data_src->nla_tracks.first; + + BLI_assert(nla_track_src != NULL); + + NlaTrack *nla_track_dst = BKE_nlatrack_copy(bmain, nla_track_src, true, 0); + + /* This handles NULL anchor as expected by adding at head of list. */ + BLI_insertlinkafter(&anim_data_dst->nla_tracks, nla_track_anchor, nla_track_dst); + + // printf("%s: We inserted a NLA Track...\n", __func__); + return true; +} + #else /* helper function for Keying Set -> keying settings */ @@ -1251,14 +1305,19 @@ static void rna_def_animdata(BlenderRNA *brna) RNA_def_property_collection_sdna(prop, NULL, "nla_tracks", NULL); RNA_def_property_struct_type(prop, "NlaTrack"); RNA_def_property_ui_text(prop, "NLA Tracks", "NLA Tracks (i.e. Animation Layers)"); + RNA_def_property_override_flag(prop, + PROPOVERRIDE_OVERRIDABLE_LIBRARY | + PROPOVERRIDE_LIBRARY_INSERTION | PROPOVERRIDE_NO_PROP_NAME); + RNA_def_property_override_funcs(prop, NULL, NULL, "rna_NLA_tracks_override_apply"); rna_api_animdata_nla_tracks(brna, prop); + RNA_define_lib_overridable(true); + /* Active Action */ prop = RNA_def_property(srna, "action", PROP_POINTER, PROP_NONE); /* this flag as well as the dynamic test must be defined for this to be editable... */ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_pointer_funcs( prop, NULL, "rna_AnimData_action_set", NULL, "rna_Action_id_poll"); RNA_def_property_editable_func(prop, "rna_AnimData_action_editable"); @@ -1297,11 +1356,14 @@ static void rna_def_animdata(BlenderRNA *brna) prop = RNA_def_property(srna, "drivers", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "drivers", NULL); RNA_def_property_struct_type(prop, "FCurve"); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Drivers", "The Drivers/Expressions for this data-block"); + RNA_define_lib_overridable(false); + rna_api_animdata_drivers(brna, prop); + RNA_define_lib_overridable(true); + /* General Settings */ prop = RNA_def_property(srna, "use_nla", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", ADT_NLA_EVAL_OFF); @@ -1322,6 +1384,8 @@ static void rna_def_animdata(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Pin in Graph Editor", ""); RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); + RNA_define_lib_overridable(false); + /* Animation Data API */ RNA_api_animdata(srna); } diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index d586f222203..1628c978c30 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -245,7 +245,7 @@ static char *rna_Bone_path(PointerRNA *ptr) Bone *bone = (Bone *)ptr->data; char name_esc[sizeof(bone->name) * 2]; - BLI_strescape(name_esc, bone->name, sizeof(name_esc)); + BLI_str_escape(name_esc, bone->name, sizeof(name_esc)); /* special exception for trying to get the path where ID-block is Object * - this will be assumed to be from a Pose Bone... diff --git a/source/blender/makesrna/intern/rna_asset.c b/source/blender/makesrna/intern/rna_asset.c new file mode 100644 index 00000000000..1af53e95cc9 --- /dev/null +++ b/source/blender/makesrna/intern/rna_asset.c @@ -0,0 +1,228 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup RNA + */ + +#include <stdlib.h> + +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "DNA_asset_types.h" +#include "DNA_defs.h" + +#include "rna_internal.h" + +#ifdef RNA_RUNTIME + +# include "BKE_asset.h" +# include "BKE_idprop.h" + +# include "BLI_listbase.h" + +# include "RNA_access.h" + +static AssetTag *rna_AssetMetaData_tag_new(AssetMetaData *asset_data, + ReportList *reports, + const char *name, + bool skip_if_exists) +{ + AssetTag *tag = NULL; + + if (skip_if_exists) { + struct AssetTagEnsureResult result = BKE_asset_metadata_tag_ensure(asset_data, name); + + if (!result.is_new) { + BKE_reportf( + reports, RPT_WARNING, "Tag '%s' already present for given asset", result.tag->name); + /* Report, but still return valid item. */ + } + tag = result.tag; + } + else { + tag = BKE_asset_metadata_tag_add(asset_data, name); + } + + return tag; +} + +static void rna_AssetMetaData_tag_remove(AssetMetaData *asset_data, + ReportList *reports, + PointerRNA *tag_ptr) +{ + AssetTag *tag = tag_ptr->data; + if (BLI_findindex(&asset_data->tags, tag) == -1) { + BKE_reportf(reports, RPT_ERROR, "Tag '%s' not found in given asset", tag->name); + return; + } + + BKE_asset_metadata_tag_remove(asset_data, tag); + RNA_POINTER_INVALIDATE(tag_ptr); +} + +static IDProperty *rna_AssetMetaData_idprops(PointerRNA *ptr, bool create) +{ + AssetMetaData *asset_data = ptr->data; + + if (create && !asset_data->properties) { + IDPropertyTemplate val = {0}; + asset_data->properties = IDP_New(IDP_GROUP, &val, "RNA_AssetMetaData group"); + } + + return asset_data->properties; +} + +static void rna_AssetMetaData_description_get(PointerRNA *ptr, char *value) +{ + AssetMetaData *asset_data = ptr->data; + + if (asset_data->description) { + strcpy(value, asset_data->description); + } + else { + value[0] = '\0'; + } +} + +static int rna_AssetMetaData_description_length(PointerRNA *ptr) +{ + AssetMetaData *asset_data = ptr->data; + return asset_data->description ? strlen(asset_data->description) : 0; +} + +static void rna_AssetMetaData_description_set(PointerRNA *ptr, const char *value) +{ + AssetMetaData *asset_data = ptr->data; + + if (asset_data->description) { + MEM_freeN(asset_data->description); + } + + if (value[0]) { + asset_data->description = BLI_strdup(value); + } + else { + asset_data->description = NULL; + } +} + +static void rna_AssetMetaData_active_tag_range( + PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax) +{ + const AssetMetaData *asset_data = ptr->data; + *min = *softmin = 0; + *max = *softmax = MAX2(asset_data->tot_tags - 1, 0); +} + +#else + +static void rna_def_asset_tag(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "AssetTag", NULL); + RNA_def_struct_ui_text(srna, "Asset Tag", "User defined tag (name token)"); + + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_string_maxlength(prop, MAX_NAME); + RNA_def_property_ui_text(prop, "Name", "The identifier that makes up this tag"); + RNA_def_struct_name_property(srna, prop); +} + +static void rna_def_asset_tags_api(BlenderRNA *brna, PropertyRNA *cprop) +{ + StructRNA *srna; + + FunctionRNA *func; + PropertyRNA *parm; + + RNA_def_property_srna(cprop, "AssetTags"); + srna = RNA_def_struct(brna, "AssetTags", NULL); + RNA_def_struct_sdna(srna, "AssetMetaData"); + RNA_def_struct_ui_text(srna, "Asset Tags", "Collection of custom asset tags"); + + /* Tag collection */ + func = RNA_def_function(srna, "new", "rna_AssetMetaData_tag_new"); + RNA_def_function_ui_description(func, "Add a new tag to this asset"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); + parm = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_boolean(func, + "skip_if_exists", + false, + "Skip if Exists", + "Do not add a new tag if one of the same type already exists"); + /* return type */ + parm = RNA_def_pointer(func, "tag", "AssetTag", "", "New tag"); + RNA_def_function_return(func, parm); + + func = RNA_def_function(srna, "remove", "rna_AssetMetaData_tag_remove"); + RNA_def_function_ui_description(func, "Remove an existing tag from this asset"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); + /* tag to remove */ + parm = RNA_def_pointer(func, "tag", "AssetTag", "", "Removed tag"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); +} + +static void rna_def_asset_data(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "AssetMetaData", NULL); + RNA_def_struct_ui_text(srna, "Asset Data", "Additional data stored for an asset data-block"); + // RNA_def_struct_ui_icon(srna, ICON_ASSET); /* TODO: Icon doesn't exist!. */ + /* The struct has custom properties, but no pointer properties to other IDs! */ + RNA_def_struct_idprops_func(srna, "rna_AssetMetaData_idprops"); + RNA_def_struct_flag(srna, STRUCT_NO_DATABLOCK_IDPROPERTIES); /* Mandatory! */ + + prop = RNA_def_property(srna, "description", PROP_STRING, PROP_NONE); + RNA_def_property_string_funcs(prop, + "rna_AssetMetaData_description_get", + "rna_AssetMetaData_description_length", + "rna_AssetMetaData_description_set"); + RNA_def_property_ui_text( + prop, "Description", "A description of the asset to be displayed for the user"); + + prop = RNA_def_property(srna, "tags", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "AssetTag"); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, + "Tags", + "Custom tags (name tokens) for the asset, used for filtering and " + "general asset management"); + rna_def_asset_tags_api(brna, prop); + + prop = RNA_def_property(srna, "active_tag", PROP_INT, PROP_NONE); + RNA_def_property_int_funcs(prop, NULL, NULL, "rna_AssetMetaData_active_tag_range"); + RNA_def_property_ui_text(prop, "Active Tag", "Index of the tag set for editing"); +} + +void RNA_def_asset(BlenderRNA *brna) +{ + RNA_define_animate_sdna(false); + + rna_def_asset_tag(brna); + rna_def_asset_data(brna); + + RNA_define_animate_sdna(true); +} + +#endif diff --git a/source/blender/makesrna/intern/rna_attribute.c b/source/blender/makesrna/intern/rna_attribute.c index ad615026343..e9d258424d8 100644 --- a/source/blender/makesrna/intern/rna_attribute.c +++ b/source/blender/makesrna/intern/rna_attribute.c @@ -38,12 +38,13 @@ #include "WM_types.h" const EnumPropertyItem rna_enum_attribute_type_items[] = { - {CD_PROP_FLOAT, "FLOAT", 0, "Float", "Floating point value"}, - {CD_PROP_INT32, "INT", 0, "Integer", "32 bit integer"}, - {CD_PROP_FLOAT3, "FLOAT_VECTOR", 0, "Vector", "3D vector with floating point values"}, - {CD_PROP_COLOR, "FLOAT_COLOR", 0, "Float Color", "RGBA color with floating point precisions"}, + {CD_PROP_FLOAT, "FLOAT", 0, "Float", "Floating-point value"}, + {CD_PROP_INT32, "INT", 0, "Integer", "32-bit integer"}, + {CD_PROP_FLOAT3, "FLOAT_VECTOR", 0, "Vector", "3D vector with floating-point values"}, + {CD_PROP_COLOR, "FLOAT_COLOR", 0, "Color", "RGBA color with floating-point precisions"}, {CD_MLOOPCOL, "BYTE_COLOR", 0, "Byte Color", "RGBA color with 8-bit precision"}, {CD_PROP_STRING, "STRING", 0, "String", "Text string"}, + {CD_PROP_BOOL, "BOOLEAN", 0, "Boolean", "True or false"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/makesrna/intern/rna_boid.c b/source/blender/makesrna/intern/rna_boid.c index 33d69f6f912..3e3452af713 100644 --- a/source/blender/makesrna/intern/rna_boid.c +++ b/source/blender/makesrna/intern/rna_boid.c @@ -183,7 +183,7 @@ static char *rna_BoidRule_path(PointerRNA *ptr) BoidRule *rule = (BoidRule *)ptr->data; char name_esc[sizeof(rule->name) * 2]; - BLI_strescape(name_esc, rule->name, sizeof(name_esc)); + BLI_str_escape(name_esc, rule->name, sizeof(name_esc)); return BLI_sprintfN("rules[\"%s\"]", name_esc); /* XXX not unique */ } diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index 1337994f5a4..4b78ebf45e5 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -22,6 +22,7 @@ #include "DNA_brush_types.h" #include "DNA_gpencil_types.h" +#include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_texture_types.h" @@ -133,10 +134,11 @@ const EnumPropertyItem rna_enum_brush_sculpt_tool_items[] = { {SCULPT_TOOL_SIMPLIFY, "SIMPLIFY", ICON_BRUSH_DATA, "Simplify", ""}, {SCULPT_TOOL_MASK, "MASK", ICON_BRUSH_MASK, "Mask", ""}, {SCULPT_TOOL_DISPLACEMENT_ERASER, "DISPLACEMENT_ERASER", ICON_BRUSH_SCULPT_DRAW, "Multires Displacement Eraser", ""}, - {SCULPT_TOOL_PAINT, "PAINT", ICON_BRUSH_SCULPT_DRAW, "Paint", ""}, + {SCULPT_TOOL_DISPLACEMENT_SMEAR, "DISPLACEMENT_SMEAR", ICON_BRUSH_SCULPT_DRAW, "Multires Displacement Smear", ""}, + {SCULPT_TOOL_PAINT, "PAINT", ICON_BRUSH_PAINT, "Paint", ""}, {SCULPT_TOOL_SMEAR, "SMEAR", ICON_BRUSH_SCULPT_DRAW, "Smear", ""}, {SCULPT_TOOL_DRAW_FACE_SETS, "DRAW_FACE_SETS", ICON_BRUSH_MASK, "Draw Face Sets", ""}, - {SCULPT_TOOL_VCOL_BOUNDARY, "VCOL_BOUNDARY", ICON_BRUSH_VCOL_BOUNDARY, "Color Boundary", ""}, + {SCULPT_TOOL_VCOL_BOUNDARY, "VCOL_BOUNDARY", ICON_BRUSH_VCOL_BOUNDARY, "Sharpen Color Boundary", ""}, {0, NULL, 0, NULL, NULL}, }; /* clang-format on */ @@ -2080,6 +2082,20 @@ static void rna_def_brush(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}, }; + static const EnumPropertyItem brush_snake_hook_deform_type_items[] = { + {BRUSH_SNAKE_HOOK_DEFORM_FALLOFF, + "FALLOFF", + 0, + "Radius Falloff", + "Applies the brush falloff in the tip of the brush"}, + {BRUSH_SNAKE_HOOK_DEFORM_ELASTIC, + "ELASTIC", + 0, + "Elastic", + "Modifies the entire mesh using elastic deform"}, + {0, NULL, 0, NULL, NULL}, + }; + static const EnumPropertyItem brush_cloth_deform_type_items[] = { {BRUSH_CLOTH_DEFORM_DRAG, "DRAG", 0, "Drag", ""}, {BRUSH_CLOTH_DEFORM_PUSH, "PUSH", 0, "Push", ""}, @@ -2317,6 +2333,11 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Deformation", "Deformation type that is used in the brush"); RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "snake_hook_deform_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, brush_snake_hook_deform_type_items); + RNA_def_property_ui_text(prop, "Deformation", "Deformation type that is used in the brush"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "cloth_deform_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, brush_cloth_deform_type_items); RNA_def_property_ui_text(prop, "Deformation", "Deformation type that is used in the brush"); diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c index 1810cee5cee..9d0ee90de60 100644 --- a/source/blender/makesrna/intern/rna_camera.c +++ b/source/blender/makesrna/intern/rna_camera.c @@ -40,7 +40,7 @@ # include "DEG_depsgraph.h" # include "DEG_depsgraph_build.h" -# include "SEQ_sequencer.h" +# include "SEQ_relations.h" static float rna_Camera_angle_get(PointerRNA *ptr) { @@ -127,7 +127,7 @@ static void rna_Camera_background_images_clear(Camera *cam) static void rna_Camera_dof_update(Main *bmain, Scene *scene, PointerRNA *UNUSED(ptr)) { - BKE_sequence_invalidate_scene_strips(bmain, scene); + SEQ_relations_invalidate_scene_strips(bmain, scene); WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene); } @@ -662,7 +662,7 @@ void RNA_def_camera(BlenderRNA *brna) prop = RNA_def_property(srna, "show_safe_center", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", CAM_SHOW_SAFE_CENTER); RNA_def_property_ui_text(prop, - "Show Center-cut safe areas", + "Show Center-Cut Safe Areas", "Show safe areas to fit content in a different aspect ratio"); RNA_def_property_update(prop, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, NULL); diff --git a/source/blender/makesrna/intern/rna_cloth.c b/source/blender/makesrna/intern/rna_cloth.c index 27318494428..b0e0b577629 100644 --- a/source/blender/makesrna/intern/rna_cloth.c +++ b/source/blender/makesrna/intern/rna_cloth.c @@ -439,7 +439,7 @@ static char *rna_ClothSettings_path(PointerRNA *ptr) if (md) { char name_esc[sizeof(md->name) * 2]; - BLI_strescape(name_esc, md->name, sizeof(name_esc)); + BLI_str_escape(name_esc, md->name, sizeof(name_esc)); return BLI_sprintfN("modifiers[\"%s\"].settings", name_esc); } else { @@ -454,7 +454,7 @@ static char *rna_ClothCollisionSettings_path(PointerRNA *ptr) if (md) { char name_esc[sizeof(md->name) * 2]; - BLI_strescape(name_esc, md->name, sizeof(name_esc)); + BLI_str_escape(name_esc, md->name, sizeof(name_esc)); return BLI_sprintfN("modifiers[\"%s\"].collision_settings", name_esc); } else { diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c index ac47f434c3b..39aeeb430c2 100644 --- a/source/blender/makesrna/intern/rna_color.c +++ b/source/blender/makesrna/intern/rna_color.c @@ -60,7 +60,8 @@ # include "IMB_colormanagement.h" # include "IMB_imbuf.h" -# include "SEQ_sequencer.h" +# include "SEQ_iterator.h" +# include "SEQ_relations.h" static int rna_CurveMapping_curves_length(PointerRNA *ptr) { @@ -608,14 +609,14 @@ static void rna_ColorManagedColorspaceSettings_reload_update(Main *bmain, MovieClip *clip = (MovieClip *)id; DEG_id_tag_update(&clip->id, ID_RECALC_SOURCE); - BKE_sequence_invalidate_movieclip_strips(bmain, clip); + SEQ_relations_invalidate_movieclip_strips(bmain, clip); WM_main_add_notifier(NC_MOVIECLIP | ND_DISPLAY, &clip->id); WM_main_add_notifier(NC_MOVIECLIP | NA_EDITED, &clip->id); } else if (GS(id->name) == ID_SCE) { Scene *scene = (Scene *)id; - BKE_sequence_invalidate_scene_strips(bmain, scene); + SEQ_relations_invalidate_scene_strips(bmain, scene); if (scene->ed) { ColorManagedColorspaceSettings *colorspace_settings = (ColorManagedColorspaceSettings *) @@ -634,18 +635,18 @@ static void rna_ColorManagedColorspaceSettings_reload_update(Main *bmain, } if (seq_found) { - BKE_sequence_free_anim(seq); + SEQ_relations_sequence_free_anim(seq); if (seq->strip->proxy && seq->strip->proxy->anim) { IMB_free_anim(seq->strip->proxy->anim); seq->strip->proxy->anim = NULL; } - BKE_sequence_invalidate_cache_preprocessed(scene, seq); + SEQ_relations_invalidate_cache_preprocessed(scene, seq); } else { SEQ_ALL_BEGIN (scene->ed, seq) { - BKE_sequence_free_anim(seq); + SEQ_relations_sequence_free_anim(seq); } SEQ_ALL_END; } diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index 170de68a038..4f5828311d8 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -433,13 +433,13 @@ static char *rna_Constraint_do_compute_path(Object *ob, bConstraint *con) if (pchan) { char name_esc_pchan[sizeof(pchan->name) * 2]; char name_esc_const[sizeof(con->name) * 2]; - BLI_strescape(name_esc_pchan, pchan->name, sizeof(name_esc_pchan)); - BLI_strescape(name_esc_const, con->name, sizeof(name_esc_const)); + BLI_str_escape(name_esc_pchan, pchan->name, sizeof(name_esc_pchan)); + BLI_str_escape(name_esc_const, con->name, sizeof(name_esc_const)); return BLI_sprintfN("pose.bones[\"%s\"].constraints[\"%s\"]", name_esc_pchan, name_esc_const); } else { char name_esc_const[sizeof(con->name) * 2]; - BLI_strescape(name_esc_const, con->name, sizeof(name_esc_const)); + BLI_str_escape(name_esc_const, con->name, sizeof(name_esc_const)); return BLI_sprintfN("constraints[\"%s\"]", name_esc_const); } } @@ -856,7 +856,7 @@ static void rna_def_constraint_headtail_common(StructRNA *srna) prop = RNA_def_property(srna, "head_tail", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, "bConstraint", "headtail"); - RNA_def_property_ui_text(prop, "Head/Tail", "Target along length of bone: Head=0, Tail=1"); + RNA_def_property_ui_text(prop, "Head/Tail", "Target along length of bone: Head is 0, Tail is 1"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); prop = RNA_def_property(srna, "use_bbone_shape", PROP_BOOLEAN, PROP_NONE); @@ -1051,7 +1051,7 @@ static void rna_def_constraint_python(BlenderRNA *brna) prop = RNA_def_property(srna, "target_count", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "tarnum"); - RNA_def_property_ui_text(prop, "Number of Targets", "Usually only 1-3 are needed"); + RNA_def_property_ui_text(prop, "Number of Targets", "Usually only 1 to 3 are needed"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update"); prop = RNA_def_property(srna, "text", PROP_POINTER, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_dynamicpaint.c b/source/blender/makesrna/intern/rna_dynamicpaint.c index f86cfb674d1..7c4762aa3a3 100644 --- a/source/blender/makesrna/intern/rna_dynamicpaint.c +++ b/source/blender/makesrna/intern/rna_dynamicpaint.c @@ -57,7 +57,7 @@ static char *rna_DynamicPaintCanvasSettings_path(PointerRNA *ptr) ModifierData *md = (ModifierData *)settings->pmd; char name_esc[sizeof(md->name) * 2]; - BLI_strescape(name_esc, md->name, sizeof(name_esc)); + BLI_str_escape(name_esc, md->name, sizeof(name_esc)); return BLI_sprintfN("modifiers[\"%s\"].canvas_settings", name_esc); } @@ -67,7 +67,7 @@ static char *rna_DynamicPaintBrushSettings_path(PointerRNA *ptr) ModifierData *md = (ModifierData *)settings->pmd; char name_esc[sizeof(md->name) * 2]; - BLI_strescape(name_esc, md->name, sizeof(name_esc)); + BLI_str_escape(name_esc, md->name, sizeof(name_esc)); return BLI_sprintfN("modifiers[\"%s\"].brush_settings", name_esc); } @@ -78,8 +78,8 @@ static char *rna_DynamicPaintSurface_path(PointerRNA *ptr) char name_esc[sizeof(md->name) * 2]; char name_esc_surface[sizeof(surface->name) * 2]; - BLI_strescape(name_esc, md->name, sizeof(name_esc)); - BLI_strescape(name_esc_surface, surface->name, sizeof(name_esc_surface)); + BLI_str_escape(name_esc, md->name, sizeof(name_esc)); + BLI_str_escape(name_esc_surface, surface->name, sizeof(name_esc_surface)); return BLI_sprintfN( "modifiers[\"%s\"].canvas_settings.canvas_surfaces[\"%s\"]", name_esc, name_esc_surface); } diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c index 8734984d4e1..475b4d33936 100644 --- a/source/blender/makesrna/intern/rna_fcurve.c +++ b/source/blender/makesrna/intern/rna_fcurve.c @@ -2341,7 +2341,7 @@ static void rna_def_fcurve(BlenderRNA *brna) RNA_def_property_update(prop, NC_ANIMATION, "rna_FCurve_update_data_relations"); /* called 'index' when given as function arg */ - prop = RNA_def_property(srna, "array_index", PROP_INT, PROP_NONE); + prop = RNA_def_property(srna, "array_index", PROP_INT, PROP_UNSIGNED); RNA_def_property_ui_text( prop, "RNA Array Index", "Index to the specific property affected by F-Curve if applicable"); /* XXX need an update callback for this so that animation gets evaluated */ diff --git a/source/blender/makesrna/intern/rna_fluid.c b/source/blender/makesrna/intern/rna_fluid.c index 02ae71e3b3d..bb8280ede91 100644 --- a/source/blender/makesrna/intern/rna_fluid.c +++ b/source/blender/makesrna/intern/rna_fluid.c @@ -872,7 +872,7 @@ static char *rna_FluidDomainSettings_path(PointerRNA *ptr) ModifierData *md = (ModifierData *)settings->fmd; char name_esc[sizeof(md->name) * 2]; - BLI_strescape(name_esc, md->name, sizeof(name_esc)); + BLI_str_escape(name_esc, md->name, sizeof(name_esc)); return BLI_sprintfN("modifiers[\"%s\"].domain_settings", name_esc); } @@ -882,7 +882,7 @@ static char *rna_FluidFlowSettings_path(PointerRNA *ptr) ModifierData *md = (ModifierData *)settings->fmd; char name_esc[sizeof(md->name) * 2]; - BLI_strescape(name_esc, md->name, sizeof(name_esc)); + BLI_str_escape(name_esc, md->name, sizeof(name_esc)); return BLI_sprintfN("modifiers[\"%s\"].flow_settings", name_esc); } @@ -892,7 +892,7 @@ static char *rna_FluidEffectorSettings_path(PointerRNA *ptr) ModifierData *md = (ModifierData *)settings->fmd; char name_esc[sizeof(md->name) * 2]; - BLI_strescape(name_esc, md->name, sizeof(name_esc)); + BLI_str_escape(name_esc, md->name, sizeof(name_esc)); return BLI_sprintfN("modifiers[\"%s\"].effector_settings", name_esc); } @@ -1552,7 +1552,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna) RNA_def_property_dynamic_array_funcs(prop, "rna_FluidModifier_grid_get_length"); RNA_def_property_float_funcs(prop, "rna_FluidModifier_temperature_grid_get", NULL, NULL); RNA_def_property_ui_text( - prop, "Temperature Grid", "Smoke temperature grid, range 0..1 represents 0..1000K"); + prop, "Temperature Grid", "Smoke temperature grid, range 0 to 1 represents 0 to 1000K"); # endif /* WITH_FLUID */ /* domain object data */ diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index 603bd51b2d9..72e11838fac 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -308,7 +308,7 @@ static char *rna_GPencilLayer_path(PointerRNA *ptr) bGPDlayer *gpl = (bGPDlayer *)ptr->data; char name_esc[sizeof(gpl->info) * 2]; - BLI_strescape(name_esc, gpl->info, sizeof(name_esc)); + BLI_str_escape(name_esc, gpl->info, sizeof(name_esc)); return BLI_sprintfN("layers[\"%s\"]", name_esc); } @@ -403,13 +403,13 @@ static char *rna_GPencilLayerMask_path(PointerRNA *ptr) bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); bGPDlayer_Mask *mask = (bGPDlayer_Mask *)ptr->data; - char name_layer[sizeof(gpl->info) * 2]; - char name_mask[sizeof(mask->name) * 2]; + char gpl_info_esc[sizeof(gpl->info) * 2]; + char mask_name_esc[sizeof(mask->name) * 2]; - BLI_strescape(name_layer, gpl->info, sizeof(name_layer)); - BLI_strescape(name_mask, mask->name, sizeof(name_mask)); + BLI_str_escape(gpl_info_esc, gpl->info, sizeof(gpl_info_esc)); + BLI_str_escape(mask_name_esc, mask->name, sizeof(mask_name_esc)); - return BLI_sprintfN("layers[\"%s\"].mask_layers[\"%s\"]", name_layer, name_mask); + return BLI_sprintfN("layers[\"%s\"].mask_layers[\"%s\"]", gpl_info_esc, mask_name_esc); } static int rna_GPencil_active_mask_index_get(PointerRNA *ptr) diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c index e30ee2e9ee7..89eb989a442 100644 --- a/source/blender/makesrna/intern/rna_gpencil_modifier.c +++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c @@ -276,7 +276,7 @@ static char *rna_GpencilModifier_path(PointerRNA *ptr) GpencilModifierData *gmd = ptr->data; char name_esc[sizeof(gmd->name) * 2]; - BLI_strescape(name_esc, gmd->name, sizeof(name_esc)); + BLI_str_escape(name_esc, gmd->name, sizeof(name_esc)); return BLI_sprintfN("grease_pencil_modifiers[\"%s\"]", name_esc); } @@ -1560,6 +1560,12 @@ static void rna_def_modifier_gpencilarray(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_ARRAY_USE_RELATIVE); RNA_def_property_ui_text(prop, "Shift", "Enable shift"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "use_uniform_random_scale", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_ARRAY_UNIFORM_RANDOM_SCALE); + RNA_def_property_ui_text( + prop, "Uniform Scale", "Use the same random seed for each scale axis for a uniform scale"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); } static void rna_def_modifier_gpencilbuild(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c index 504a4a6bdf3..cf4b343e2f7 100644 --- a/source/blender/makesrna/intern/rna_image.c +++ b/source/blender/makesrna/intern/rna_image.c @@ -598,6 +598,7 @@ static void rna_render_slots_active_set(PointerRNA *ptr, int index = BLI_findindex(&image->renderslots, slot); if (index != -1) { image->render_slot = index; + image->gpuflag |= IMA_GPU_REFRESH; } } } @@ -613,6 +614,7 @@ static void rna_render_slots_active_index_set(PointerRNA *ptr, int value) Image *image = (Image *)ptr->owner_id; int num_slots = BLI_listbase_count(&image->renderslots); image->render_slot = value; + image->gpuflag |= IMA_GPU_REFRESH; CLAMP(image->render_slot, 0, num_slots - 1); } @@ -1136,7 +1138,7 @@ static void rna_def_image(BlenderRNA *brna) RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", IMA_HIGH_BITDEPTH); RNA_def_property_ui_text(prop, "Half Float Precision", - "Use 16bits per channel to lower the memory usage during rendering"); + "Use 16 bits per channel to lower the memory usage during rendering"); RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_gpu_texture_update"); /* multiview */ diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index 1c6f83efd65..76c3e17e128 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -152,6 +152,7 @@ void RNA_def_animation(struct BlenderRNA *brna); void RNA_def_animviz(struct BlenderRNA *brna); void RNA_def_armature(struct BlenderRNA *brna); void RNA_def_attribute(struct BlenderRNA *brna); +void RNA_def_asset(struct BlenderRNA *brna); void RNA_def_boid(struct BlenderRNA *brna); void RNA_def_brush(struct BlenderRNA *brna); void RNA_def_cachefile(struct BlenderRNA *brna); @@ -470,7 +471,9 @@ void RNA_def_main_lightprobes(BlenderRNA *brna, PropertyRNA *cprop); #ifdef WITH_HAIR_NODES void RNA_def_main_hairs(BlenderRNA *brna, PropertyRNA *cprop); #endif +#ifdef WITH_POINT_CLOUD void RNA_def_main_pointclouds(BlenderRNA *brna, PropertyRNA *cprop); +#endif void RNA_def_main_volumes(BlenderRNA *brna, PropertyRNA *cprop); #ifdef WITH_GEOMETRY_NODES void RNA_def_main_simulations(BlenderRNA *brna, PropertyRNA *cprop); diff --git a/source/blender/makesrna/intern/rna_key.c b/source/blender/makesrna/intern/rna_key.c index e0005766c48..3b9fc970072 100644 --- a/source/blender/makesrna/intern/rna_key.c +++ b/source/blender/makesrna/intern/rna_key.c @@ -676,7 +676,7 @@ static char *rna_ShapeKey_path(PointerRNA *ptr) ID *id = ptr->owner_id; char name_esc[sizeof(kb->name) * 2]; - BLI_strescape(name_esc, kb->name, sizeof(name_esc)); + BLI_str_escape(name_esc, kb->name, sizeof(name_esc)); if ((id) && (GS(id->name) != ID_KE)) { return BLI_sprintfN("shape_keys.key_blocks[\"%s\"]", name_esc); @@ -774,7 +774,7 @@ static char *rna_ShapeKeyPoint_path(PointerRNA *ptr) index = rna_ShapeKey_curve_find_index(key, index); } - BLI_strescape(name_esc_kb, kb->name, sizeof(name_esc_kb)); + BLI_str_escape(name_esc_kb, kb->name, sizeof(name_esc_kb)); if (GS(id->name) == ID_KE) { return BLI_sprintfN("key_blocks[\"%s\"].data[%d]", name_esc_kb, index); diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c index abc4136bae8..afe69c37eef 100644 --- a/source/blender/makesrna/intern/rna_layer.c +++ b/source/blender/makesrna/intern/rna_layer.c @@ -115,7 +115,7 @@ static char *rna_ViewLayer_path(PointerRNA *ptr) ViewLayer *srl = (ViewLayer *)ptr->data; char name_esc[sizeof(srl->name) * 2]; - BLI_strescape(name_esc, srl->name, sizeof(name_esc)); + BLI_str_escape(name_esc, srl->name, sizeof(name_esc)); return BLI_sprintfN("view_layers[\"%s\"]", name_esc); } diff --git a/source/blender/makesrna/intern/rna_light.c b/source/blender/makesrna/intern/rna_light.c index e43079c967f..433d499b4c1 100644 --- a/source/blender/makesrna/intern/rna_light.c +++ b/source/blender/makesrna/intern/rna_light.c @@ -127,7 +127,7 @@ static void rna_def_light(BlenderRNA *brna) prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, rna_enum_light_type_items); - RNA_def_property_ui_text(prop, "Type", "Type of Light"); + RNA_def_property_ui_text(prop, "Type", "Type of light"); RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_LIGHT); RNA_def_property_update(prop, 0, "rna_Light_draw_update"); diff --git a/source/blender/makesrna/intern/rna_linestyle.c b/source/blender/makesrna/intern/rna_linestyle.c index 03442748854..ca97f2c9a55 100644 --- a/source/blender/makesrna/intern/rna_linestyle.c +++ b/source/blender/makesrna/intern/rna_linestyle.c @@ -257,7 +257,7 @@ static char *rna_LineStyle_color_modifier_path(PointerRNA *ptr) { LineStyleModifier *m = (LineStyleModifier *)ptr->data; char name_esc[sizeof(m->name) * 2]; - BLI_strescape(name_esc, m->name, sizeof(name_esc)); + BLI_str_escape(name_esc, m->name, sizeof(name_esc)); return BLI_sprintfN("color_modifiers[\"%s\"]", name_esc); } @@ -265,7 +265,7 @@ static char *rna_LineStyle_alpha_modifier_path(PointerRNA *ptr) { LineStyleModifier *m = (LineStyleModifier *)ptr->data; char name_esc[sizeof(m->name) * 2]; - BLI_strescape(name_esc, m->name, sizeof(name_esc)); + BLI_str_escape(name_esc, m->name, sizeof(name_esc)); return BLI_sprintfN("alpha_modifiers[\"%s\"]", name_esc); } @@ -273,7 +273,7 @@ static char *rna_LineStyle_thickness_modifier_path(PointerRNA *ptr) { LineStyleModifier *m = (LineStyleModifier *)ptr->data; char name_esc[sizeof(m->name) * 2]; - BLI_strescape(name_esc, m->name, sizeof(name_esc)); + BLI_str_escape(name_esc, m->name, sizeof(name_esc)); return BLI_sprintfN("thickness_modifiers[\"%s\"]", name_esc); } @@ -281,7 +281,7 @@ static char *rna_LineStyle_geometry_modifier_path(PointerRNA *ptr) { LineStyleModifier *m = (LineStyleModifier *)ptr->data; char name_esc[sizeof(m->name) * 2]; - BLI_strescape(name_esc, m->name, sizeof(name_esc)); + BLI_str_escape(name_esc, m->name, sizeof(name_esc)); return BLI_sprintfN("geometry_modifiers[\"%s\"]", name_esc); } diff --git a/source/blender/makesrna/intern/rna_main.c b/source/blender/makesrna/intern/rna_main.c index 0f17f8c44cd..aa22a4307d2 100644 --- a/source/blender/makesrna/intern/rna_main.c +++ b/source/blender/makesrna/intern/rna_main.c @@ -128,7 +128,9 @@ RNA_MAIN_LISTBASE_FUNCS_DEF(objects) RNA_MAIN_LISTBASE_FUNCS_DEF(paintcurves) RNA_MAIN_LISTBASE_FUNCS_DEF(palettes) RNA_MAIN_LISTBASE_FUNCS_DEF(particles) +# ifdef WITH_POINT_CLOUD RNA_MAIN_LISTBASE_FUNCS_DEF(pointclouds) +# endif RNA_MAIN_LISTBASE_FUNCS_DEF(scenes) RNA_MAIN_LISTBASE_FUNCS_DEF(screens) RNA_MAIN_LISTBASE_FUNCS_DEF(shapekeys) @@ -391,12 +393,14 @@ void RNA_def_main(BlenderRNA *brna) # ifdef WITH_HAIR_NODES {"hairs", "Hair", "rna_Main_hairs_begin", "Hairs", "Hair data-blocks", RNA_def_main_hairs}, # endif +# ifdef WITH_POINT_CLOUD {"pointclouds", "PointCloud", "rna_Main_pointclouds_begin", "Point Clouds", "Point cloud data-blocks", RNA_def_main_pointclouds}, +# endif {"volumes", "Volume", "rna_Main_volumes_begin", diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index 5fc2cce9bc6..21ff44ed253 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -678,6 +678,7 @@ static Hair *rna_Main_hairs_new(Main *bmain, const char *name) } # endif +# ifdef WITH_POINT_CLOUD static PointCloud *rna_Main_pointclouds_new(Main *bmain, const char *name) { char safe_name[MAX_ID_NAME - 2]; @@ -687,6 +688,7 @@ static PointCloud *rna_Main_pointclouds_new(Main *bmain, const char *name) id_us_min(&pointcloud->id); return pointcloud; } +# endif static Volume *rna_Main_volumes_new(Main *bmain, const char *name) { @@ -755,7 +757,9 @@ RNA_MAIN_ID_TAG_FUNCS_DEF(lightprobes, lightprobes, ID_LP) # ifdef WITH_HAIR_NODES RNA_MAIN_ID_TAG_FUNCS_DEF(hairs, hairs, ID_HA) # endif +# ifdef WITH_POINT_CLOUD RNA_MAIN_ID_TAG_FUNCS_DEF(pointclouds, pointclouds, ID_PT) +# endif RNA_MAIN_ID_TAG_FUNCS_DEF(volumes, volumes, ID_VO) # ifdef WITH_GEOMETRY_NODES RNA_MAIN_ID_TAG_FUNCS_DEF(simulations, simulations, ID_SIM) @@ -2206,6 +2210,7 @@ void RNA_def_main_hairs(BlenderRNA *brna, PropertyRNA *cprop) } # endif +# ifdef WITH_POINT_CLOUD void RNA_def_main_pointclouds(BlenderRNA *brna, PropertyRNA *cprop) { StructRNA *srna; @@ -2252,6 +2257,7 @@ void RNA_def_main_pointclouds(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_boolean(func, "value", 0, "Value", ""); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); } +# endif void RNA_def_main_volumes(BlenderRNA *brna, PropertyRNA *cprop) { diff --git a/source/blender/makesrna/intern/rna_mask.c b/source/blender/makesrna/intern/rna_mask.c index cfbaf0cccf5..db3e5195c79 100644 --- a/source/blender/makesrna/intern/rna_mask.c +++ b/source/blender/makesrna/intern/rna_mask.c @@ -182,7 +182,7 @@ static char *rna_MaskLayer_path(PointerRNA *ptr) { MaskLayer *masklay = (MaskLayer *)ptr->data; char name_esc[sizeof(masklay->name) * 2]; - BLI_strescape(name_esc, masklay->name, sizeof(name_esc)); + BLI_str_escape(name_esc, masklay->name, sizeof(name_esc)); return BLI_sprintfN("layers[\"%s\"]", name_esc); } diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index 086a182e085..94b56e4f4e0 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -683,7 +683,7 @@ void RNA_def_material(BlenderRNA *brna) {MA_SPHERE, "SPHERE", ICON_MATSPHERE, "Sphere", "Sphere"}, {MA_CUBE, "CUBE", ICON_MATCUBE, "Cube", "Cube"}, {MA_HAIR, "HAIR", ICON_HAIR, "Hair", "Hair strands"}, - {MA_SHADERBALL, "SHADERBALL", ICON_MATSHADERBALL, "Shader Ball", "Shader Ball"}, + {MA_SHADERBALL, "SHADERBALL", ICON_MATSHADERBALL, "Shader Ball", "Shader ball"}, {MA_CLOTH, "CLOTH", ICON_MATCLOTH, "Cloth", "Cloth"}, {MA_FLUID, "FLUID", ICON_MATFLUID, "Fluid", "Fluid"}, {0, NULL, 0, NULL, NULL}, diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index 4afb17fe0b9..2bbfee2dcef 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -670,7 +670,7 @@ static char *rna_MeshUVLoopLayer_path(PointerRNA *ptr) { CustomDataLayer *cdl = ptr->data; char name_esc[sizeof(cdl->name) * 2]; - BLI_strescape(name_esc, cdl->name, sizeof(name_esc)); + BLI_str_escape(name_esc, cdl->name, sizeof(name_esc)); return BLI_sprintfN("uv_layers[\"%s\"]", name_esc); } @@ -913,7 +913,7 @@ static char *rna_MeshSkinVertexLayer_path(PointerRNA *ptr) { CustomDataLayer *cdl = ptr->data; char name_esc[sizeof(cdl->name) * 2]; - BLI_strescape(name_esc, cdl->name, sizeof(name_esc)); + BLI_str_escape(name_esc, cdl->name, sizeof(name_esc)); return BLI_sprintfN("skin_vertices[\"%s\"]", name_esc); } @@ -945,7 +945,7 @@ static char *rna_MeshPaintMaskLayer_path(PointerRNA *ptr) { CustomDataLayer *cdl = ptr->data; char name_esc[sizeof(cdl->name) * 2]; - BLI_strescape(name_esc, cdl->name, sizeof(name_esc)); + BLI_str_escape(name_esc, cdl->name, sizeof(name_esc)); return BLI_sprintfN("vertex_paint_masks[\"%s\"]", name_esc); } @@ -979,7 +979,7 @@ static char *rna_MeshFaceMapLayer_path(PointerRNA *ptr) { CustomDataLayer *cdl = ptr->data; char name_esc[sizeof(cdl->name) * 2]; - BLI_strescape(name_esc, cdl->name, sizeof(name_esc)); + BLI_str_escape(name_esc, cdl->name, sizeof(name_esc)); return BLI_sprintfN("face_maps[\"%s\"]", name_esc); } @@ -1189,7 +1189,7 @@ static char *rna_VertCustomData_data_path(PointerRNA *ptr, const char *collectio b = ((char *)ptr->data - ((char *)cdl->data)) / CustomData_sizeof(type); if (b >= 0 && b < totvert) { char name_esc[sizeof(cdl->name) * 2]; - BLI_strescape(name_esc, cdl->name, sizeof(name_esc)); + BLI_str_escape(name_esc, cdl->name, sizeof(name_esc)); return BLI_sprintfN("%s[\"%s\"].data[%d]", collection, name_esc, b); } } @@ -1210,7 +1210,7 @@ static char *rna_PolyCustomData_data_path(PointerRNA *ptr, const char *collectio b = ((char *)ptr->data - ((char *)cdl->data)) / CustomData_sizeof(type); if (b >= 0 && b < totpoly) { char name_esc[sizeof(cdl->name) * 2]; - BLI_strescape(name_esc, cdl->name, sizeof(name_esc)); + BLI_str_escape(name_esc, cdl->name, sizeof(name_esc)); return BLI_sprintfN("%s[\"%s\"].data[%d]", collection, name_esc, b); } } @@ -1231,7 +1231,7 @@ static char *rna_LoopCustomData_data_path(PointerRNA *ptr, const char *collectio b = ((char *)ptr->data - ((char *)cdl->data)) / CustomData_sizeof(type); if (b >= 0 && b < totloop) { char name_esc[sizeof(cdl->name) * 2]; - BLI_strescape(name_esc, cdl->name, sizeof(name_esc)); + BLI_str_escape(name_esc, cdl->name, sizeof(name_esc)); return BLI_sprintfN("%s[\"%s\"].data[%d]", collection, name_esc, b); } } @@ -1249,7 +1249,7 @@ static char *rna_MeshLoopColorLayer_path(PointerRNA *ptr) { CustomDataLayer *cdl = ptr->data; char name_esc[sizeof(cdl->name) * 2]; - BLI_strescape(name_esc, cdl->name, sizeof(name_esc)); + BLI_str_escape(name_esc, cdl->name, sizeof(name_esc)); return BLI_sprintfN("vertex_colors[\"%s\"]", name_esc); } @@ -1262,7 +1262,7 @@ static char *rna_MeshVertColorLayer_path(PointerRNA *ptr) { CustomDataLayer *cdl = ptr->data; char name_esc[sizeof(cdl->name) * 2]; - BLI_strescape(name_esc, cdl->name, sizeof(name_esc)); + BLI_str_escape(name_esc, cdl->name, sizeof(name_esc)); return BLI_sprintfN("sculpt_vertex_colors[\"%s\"]", name_esc); } @@ -1276,14 +1276,14 @@ static char *rna_MeshVertexFloatPropertyLayer_path(PointerRNA *ptr) { CustomDataLayer *cdl = ptr->data; char name_esc[sizeof(cdl->name) * 2]; - BLI_strescape(name_esc, cdl->name, sizeof(name_esc)); + BLI_str_escape(name_esc, cdl->name, sizeof(name_esc)); return BLI_sprintfN("vertex_float_layers[\"%s\"]", name_esc); } static char *rna_MeshPolygonFloatPropertyLayer_path(PointerRNA *ptr) { CustomDataLayer *cdl = ptr->data; char name_esc[sizeof(cdl->name) * 2]; - BLI_strescape(name_esc, cdl->name, sizeof(name_esc)); + BLI_str_escape(name_esc, cdl->name, sizeof(name_esc)); return BLI_sprintfN("polygon_float_layers[\"%s\"]", name_esc); } @@ -1327,14 +1327,14 @@ static char *rna_MeshVertexIntPropertyLayer_path(PointerRNA *ptr) { CustomDataLayer *cdl = ptr->data; char name_esc[sizeof(cdl->name) * 2]; - BLI_strescape(name_esc, cdl->name, sizeof(name_esc)); + BLI_str_escape(name_esc, cdl->name, sizeof(name_esc)); return BLI_sprintfN("vertex_int_layers[\"%s\"]", name_esc); } static char *rna_MeshPolygonIntPropertyLayer_path(PointerRNA *ptr) { CustomDataLayer *cdl = ptr->data; char name_esc[sizeof(cdl->name) * 2]; - BLI_strescape(name_esc, cdl->name, sizeof(name_esc)); + BLI_str_escape(name_esc, cdl->name, sizeof(name_esc)); return BLI_sprintfN("polygon_int_layers[\"%s\"]", name_esc); } @@ -1378,14 +1378,14 @@ static char *rna_MeshVertexStringPropertyLayer_path(PointerRNA *ptr) { CustomDataLayer *cdl = ptr->data; char name_esc[sizeof(cdl->name) * 2]; - BLI_strescape(name_esc, cdl->name, sizeof(name_esc)); + BLI_str_escape(name_esc, cdl->name, sizeof(name_esc)); return BLI_sprintfN("vertex_string_layers[\"%s\"]", name_esc); } static char *rna_MeshPolygonStringPropertyLayer_path(PointerRNA *ptr) { CustomDataLayer *cdl = ptr->data; char name_esc[sizeof(cdl->name) * 2]; - BLI_strescape(name_esc, cdl->name, sizeof(name_esc)); + BLI_str_escape(name_esc, cdl->name, sizeof(name_esc)); return BLI_sprintfN("polygon_string_layers[\"%s\"]", name_esc); } diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 5d961d13399..8c984479f21 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -660,7 +660,7 @@ static char *rna_Modifier_path(PointerRNA *ptr) ModifierData *md = ptr->data; char name_esc[sizeof(md->name) * 2]; - BLI_strescape(name_esc, md->name, sizeof(name_esc)); + BLI_str_escape(name_esc, md->name, sizeof(name_esc)); return BLI_sprintfN("modifiers[\"%s\"]", name_esc); } @@ -1603,12 +1603,10 @@ static int rna_MeshSequenceCacheModifier_read_velocity_get(PointerRNA *ptr) # endif } -static bool rna_NodesModifier_node_group_poll(PointerRNA *ptr, PointerRNA value) +static bool rna_NodesModifier_node_group_poll(PointerRNA *UNUSED(ptr), PointerRNA value) { - NodesModifierData *nmd = ptr->data; bNodeTree *ntree = value.data; - UNUSED_VARS(nmd, ntree); - return true; + return ntree->type == NTREE_GEOMETRY; } static void rna_NodesModifier_node_group_update(Main *bmain, Scene *scene, PointerRNA *ptr) @@ -4884,13 +4882,13 @@ static void rna_def_modifier_screw(BlenderRNA *brna) prop = RNA_def_property(srna, "use_stretch_u", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_SCREW_UV_STRETCH_U); RNA_def_property_ui_text( - prop, "Stretch U", "Stretch the U coordinates between 0-1 when UV's are present"); + prop, "Stretch U", "Stretch the U coordinates between 0 and 1 when UV's are present"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); prop = RNA_def_property(srna, "use_stretch_v", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_SCREW_UV_STRETCH_V); RNA_def_property_ui_text( - prop, "Stretch V", "Stretch the V coordinates between 0-1 when UV's are present"); + prop, "Stretch V", "Stretch the V coordinates between 0 and 1 when UV's are present"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); # if 0 @@ -5142,7 +5140,7 @@ static void rna_def_modifier_weightvgedit(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Normalize Weights", - "Normalize the resulting weights (otherwise they are only clamped within [0.0, 1.0] range)"); + "Normalize the resulting weights (otherwise they are only clamped within 0.0 to 1.0 range)"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); prop = RNA_def_property(srna, "map_curve", PROP_POINTER, PROP_NONE); @@ -5307,7 +5305,7 @@ static void rna_def_modifier_weightvgmix(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Normalize Weights", - "Normalize the resulting weights (otherwise they are only clamped within [0.0, 1.0] range)"); + "Normalize the resulting weights (otherwise they are only clamped within 0.0 to 1.0 range)"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); RNA_define_lib_overridable(false); @@ -5431,7 +5429,7 @@ static void rna_def_modifier_weightvgproximity(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Normalize Weights", - "Normalize the resulting weights (otherwise they are only clamped within [0.0, 1.0] range)"); + "Normalize the resulting weights (otherwise they are only clamped within 0.0 to 1.0 range)"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); prop = RNA_def_property(srna, "map_curve", PROP_POINTER, PROP_NONE); @@ -5980,7 +5978,7 @@ static void rna_def_modifier_meshcache(BlenderRNA *brna) "FACTOR", 0, "Factor", - "Control playback using a value between [0, 1]"}, + "Control playback using a value between 0 and 1"}, {0, NULL, 0, NULL, NULL}, }; @@ -6238,6 +6236,12 @@ static void rna_def_modifier_weld(BlenderRNA *brna) StructRNA *srna; PropertyRNA *prop; + static const EnumPropertyItem mode_items[] = { + {MOD_WELD_MODE_ALL, "ALL", 0, "All", "Full merge by distance"}, + {MOD_WELD_MODE_CONNECTED, "CONNECTED", 0, "Connected", "Only merge along the edges"}, + {0, NULL, 0, NULL, NULL}, + }; + srna = RNA_def_struct(brna, "WeldModifier", "Modifier"); RNA_def_struct_ui_text(srna, "Weld Modifier", "Weld modifier"); RNA_def_struct_sdna(srna, "WeldModifierData"); @@ -6245,6 +6249,11 @@ static void rna_def_modifier_weld(BlenderRNA *brna) RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, mode_items); + RNA_def_property_ui_text(prop, "Mode", "Mode defines the merge rule"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "merge_threshold", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "merge_dist"); RNA_def_property_range(prop, 0, FLT_MAX); diff --git a/source/blender/makesrna/intern/rna_movieclip.c b/source/blender/makesrna/intern/rna_movieclip.c index d07a4b4fac7..d32872d1682 100644 --- a/source/blender/makesrna/intern/rna_movieclip.c +++ b/source/blender/makesrna/intern/rna_movieclip.c @@ -49,7 +49,7 @@ # include "DNA_screen_types.h" # include "DNA_space_types.h" -# include "SEQ_sequencer.h" +# include "SEQ_relations.h" static void rna_MovieClip_reload_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { @@ -76,7 +76,7 @@ static void rna_MovieClip_use_proxy_update(Main *bmain, Scene *UNUSED(scene), Po { MovieClip *clip = (MovieClip *)ptr->owner_id; BKE_movieclip_clear_cache(clip); - BKE_sequence_invalidate_movieclip_strips(bmain, clip); + SEQ_relations_invalidate_movieclip_strips(bmain, clip); } static void rna_MovieClipUser_proxy_render_settings_update(Main *bmain, @@ -105,7 +105,7 @@ static void rna_MovieClipUser_proxy_render_settings_update(Main *bmain, if (clip && (clip->flag & MCLIP_USE_PROXY)) { BKE_movieclip_clear_cache(clip); - BKE_sequence_invalidate_movieclip_strips(bmain, clip); + SEQ_relations_invalidate_movieclip_strips(bmain, clip); } break; diff --git a/source/blender/makesrna/intern/rna_nla.c b/source/blender/makesrna/intern/rna_nla.c index b0dda1237b0..2642ba82bc0 100644 --- a/source/blender/makesrna/intern/rna_nla.c +++ b/source/blender/makesrna/intern/rna_nla.c @@ -88,8 +88,8 @@ static char *rna_NlaStrip_path(PointerRNA *ptr) char name_esc_nlt[sizeof(nlt->name) * 2]; char name_esc_strip[sizeof(strip->name) * 2]; - BLI_strescape(name_esc_nlt, nlt->name, sizeof(name_esc_nlt)); - BLI_strescape(name_esc_strip, strip->name, sizeof(name_esc_strip)); + BLI_str_escape(name_esc_nlt, nlt->name, sizeof(name_esc_nlt)); + BLI_str_escape(name_esc_strip, strip->name, sizeof(name_esc_strip)); return BLI_sprintfN( "animation_data.nla_tracks[\"%s\"].strips[\"%s\"]", name_esc_nlt, name_esc_strip); } @@ -607,6 +607,8 @@ static void rna_def_nlastrip(BlenderRNA *brna) RNA_def_struct_path_func(srna, "rna_NlaStrip_path"); RNA_def_struct_ui_icon(srna, ICON_NLA); /* XXX */ + RNA_define_lib_overridable(true); + /* name property */ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); RNA_def_property_ui_text(prop, "Name", ""); @@ -782,7 +784,7 @@ static void rna_def_nlastrip(BlenderRNA *brna) prop = RNA_def_property(srna, "use_animated_time_cyclic", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_USR_TIME_CYCLIC); RNA_def_property_ui_text( - prop, "Cyclic Strip Time", "Cycle the animated time within the action start & end"); + prop, "Cyclic Strip Time", "Cycle the animated time within the action start and end"); RNA_def_property_update( prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_transform_update"); @@ -820,6 +822,8 @@ static void rna_def_nlastrip(BlenderRNA *brna) "Update range of frames referenced from action " "after tweaking strip and its keyframes"); RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update"); + + RNA_define_lib_overridable(false); } static void rna_api_nlatrack_strips(BlenderRNA *brna, PropertyRNA *cprop) @@ -877,10 +881,14 @@ static void rna_def_nlatrack(BlenderRNA *brna) /* strips collection */ prop = RNA_def_property(srna, "strips", PROP_COLLECTION, PROP_NONE); RNA_def_property_struct_type(prop, "NlaStrip"); + /* We do not support inserting or removing strips in overrides of tracks for now. */ + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "NLA Strips", "NLA Strips on this NLA-track"); rna_api_nlatrack_strips(brna, prop); + RNA_define_lib_overridable(true); + /* name property */ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); RNA_def_property_ui_text(prop, "Name", ""); @@ -920,6 +928,8 @@ static void rna_def_nlatrack(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", NLATRACK_PROTECTED); RNA_def_property_ui_text(prop, "Locked", "NLA Track is locked"); RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */ + + RNA_define_lib_overridable(false); } /* --------- */ diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 99ae1b85e0c..cbd677582a9 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -37,6 +37,7 @@ #include "BKE_animsys.h" #include "BKE_attribute.h" +#include "BKE_cryptomatte.h" #include "BKE_image.h" #include "BKE_node.h" #include "BKE_texture.h" @@ -85,6 +86,7 @@ static const EnumPropertyItem node_socket_type_items[] = { {SOCK_OBJECT, "OBJECT", 0, "Object", ""}, {SOCK_IMAGE, "IMAGE", 0, "Image", ""}, {SOCK_GEOMETRY, "GEOMETRY", 0, "Geometry", ""}, + {SOCK_COLLECTION, "COLLECTION", 0, "Collection", ""}, {0, NULL, 0, NULL, NULL}, }; @@ -98,6 +100,7 @@ static const EnumPropertyItem node_socket_data_type_items[] = { {SOCK_OBJECT, "OBJECT", 0, "Object", ""}, {SOCK_IMAGE, "IMAGE", 0, "Image", ""}, {SOCK_GEOMETRY, "GEOMETRY", 0, "Geometry", ""}, + {SOCK_COLLECTION, "COLLECTION", 0, "Collection", ""}, {0, NULL, 0, NULL, NULL}, }; @@ -272,32 +275,32 @@ const EnumPropertyItem rna_enum_node_float_compare_items[] = { {NODE_FLOAT_COMPARE_LESS_THAN, "LESS_THAN", 0, - "A < B", + "Less Than", "True when the first input is smaller than second input"}, {NODE_FLOAT_COMPARE_LESS_EQUAL, "LESS_EQUAL", 0, - "A <= B", + "Less Than or Equal", "True when the first input is smaller than the second input or equal"}, {NODE_FLOAT_COMPARE_GREATER_THAN, "GREATER_THAN", 0, - "A > B", + "Greater Than", "True when the first input is greater than the second input"}, {NODE_FLOAT_COMPARE_GREATER_EQUAL, "GREATER_EQUAL", 0, - "A >= B", + "Greater Than or Equal", "True when the first input is greater than the second input or equal"}, {NODE_FLOAT_COMPARE_EQUAL, "EQUAL", 0, - "A = B", + "Equal", "True when both inputs are approximately equal"}, {NODE_FLOAT_COMPARE_NOT_EQUAL, "NOT_EQUAL", 0, - "A != B", + "Not Equal", "True when both inputs are not approximately equal"}, {0, NULL, 0, NULL, NULL}, }; @@ -423,15 +426,65 @@ static const EnumPropertyItem rna_node_geometry_triangulate_ngon_method_items[] {0, NULL, 0, NULL, NULL}, }; -static const EnumPropertyItem rna_node_geometry_attribute_input_a_items[] = { - {0, "FLOAT", 0, "Float", ""}, - {GEO_NODE_USE_ATTRIBUTE_A, "ATTRIBUTE", 0, "Attribute", ""}, +# define ITEM_ATTRIBUTE \ + { \ + GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE, "ATTRIBUTE", 0, "Attribute", "" \ + } +# define ITEM_FLOAT \ + { \ + GEO_NODE_ATTRIBUTE_INPUT_FLOAT, "FLOAT", 0, "Float", "" \ + } +# define ITEM_VECTOR \ + { \ + GEO_NODE_ATTRIBUTE_INPUT_VECTOR, "VECTOR", 0, "Vector", "" \ + } +# define ITEM_COLOR \ + { \ + GEO_NODE_ATTRIBUTE_INPUT_COLOR, "COLOR", 0, "Color", "" \ + } +# define ITEM_BOOLEAN \ + { \ + GEO_NODE_ATTRIBUTE_INPUT_BOOLEAN, "BOOLEAN", 0, "Boolean", "" \ + } + +static const EnumPropertyItem rna_node_geometry_attribute_input_type_items_float[] = { + ITEM_ATTRIBUTE, + ITEM_FLOAT, {0, NULL, 0, NULL, NULL}, }; +static const EnumPropertyItem rna_node_geometry_attribute_input_type_items_no_boolean[] = { + ITEM_ATTRIBUTE, + ITEM_FLOAT, + ITEM_VECTOR, + ITEM_COLOR, + {0, NULL, 0, NULL, NULL}, +}; +static const EnumPropertyItem rna_node_geometry_attribute_input_type_items_any[] = { + ITEM_ATTRIBUTE, + ITEM_FLOAT, + ITEM_VECTOR, + ITEM_COLOR, + ITEM_BOOLEAN, + {0, NULL, 0, NULL, NULL}, +}; + +# undef ITEM_ATTRIBUTE +# undef ITEM_FLOAT +# undef ITEM_VECTOR +# undef ITEM_COLOR +# undef ITEM_BOOLEAN -static const EnumPropertyItem rna_node_geometry_attribute_input_b_items[] = { - {0, "FLOAT", 0, "Float", ""}, - {GEO_NODE_USE_ATTRIBUTE_B, "ATTRIBUTE", 0, "Attribute", ""}, +static const EnumPropertyItem rna_node_geometry_point_distribute_method_items[] = { + {GEO_NODE_POINT_DISTRIBUTE_RANDOM, + "RANDOM", + 0, + "Random", + "Distribute points randomly on the surface"}, + {GEO_NODE_POINT_DISTRIBUTE_POISSON, + "POISSON", + 0, + "Poisson Disk", + "Project points on the surface evenly with a Poisson disk distribution"}, {0, NULL, 0, NULL, NULL}, }; @@ -1457,7 +1510,7 @@ static char *rna_Node_path(PointerRNA *ptr) bNode *node = (bNode *)ptr->data; char name_esc[sizeof(node->name) * 2]; - BLI_strescape(name_esc, node->name, sizeof(name_esc)); + BLI_str_escape(name_esc, node->name, sizeof(name_esc)); return BLI_sprintfN("nodes[\"%s\"]", name_esc); } @@ -1484,7 +1537,7 @@ char *rna_Node_ImageUser_path(PointerRNA *ptr) continue; } - BLI_strescape(name_esc, node->name, sizeof(name_esc)); + BLI_str_escape(name_esc, node->name, sizeof(name_esc)); return BLI_sprintfN("nodes[\"%s\"].image_user", name_esc); } @@ -1859,7 +1912,7 @@ static const EnumPropertyItem *itemf_function_check( static bool attribute_random_type_supported(const EnumPropertyItem *item) { - return ELEM(item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3); + return ELEM(item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3, CD_PROP_BOOL); } static const EnumPropertyItem *rna_GeometryNodeAttributeRandom_type_itemf( bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) @@ -1879,6 +1932,30 @@ static const EnumPropertyItem *rna_GeometryNodeAttributeRandom_domain_itemf( return itemf_function_check(rna_enum_attribute_domain_items, attribute_random_domain_supported); } +static bool attribute_fill_type_supported(const EnumPropertyItem *item) +{ + return ELEM(item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3, CD_PROP_COLOR, CD_PROP_BOOL); +} +static const EnumPropertyItem *rna_GeometryNodeAttributeFill_type_itemf(bContext *UNUSED(C), + PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), + bool *r_free) +{ + *r_free = true; + return itemf_function_check(rna_enum_attribute_type_items, attribute_fill_type_supported); +} + +static bool attribute_fill_domain_supported(const EnumPropertyItem *item) +{ + return item->value == ATTR_DOMAIN_POINT; +} +static const EnumPropertyItem *rna_GeometryNodeAttributeFill_domain_itemf( + bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) +{ + *r_free = true; + return itemf_function_check(rna_enum_attribute_domain_items, attribute_fill_domain_supported); +} + static bool attribute_math_operation_supported(const EnumPropertyItem *item) { return ELEM(item->value, @@ -2463,7 +2540,7 @@ static char *rna_NodeSocket_path(PointerRNA *ptr) return NULL; } - BLI_strescape(name_esc, node->name, sizeof(name_esc)); + BLI_str_escape(name_esc, node->name, sizeof(name_esc)); if (sock->in_out == SOCK_IN) { return BLI_sprintfN("nodes[\"%s\"].inputs[%d]", name_esc, socketindex); @@ -3586,33 +3663,26 @@ static void rna_NodeCryptomatte_matte_get(PointerRNA *ptr, char *value) { bNode *node = (bNode *)ptr->data; NodeCryptomatte *nc = node->storage; - - strcpy(value, (nc->matte_id) ? nc->matte_id : ""); + char *matte_id = BKE_cryptomatte_entries_to_matte_id(nc); + strcpy(value, matte_id); + MEM_freeN(matte_id); } static int rna_NodeCryptomatte_matte_length(PointerRNA *ptr) { bNode *node = (bNode *)ptr->data; NodeCryptomatte *nc = node->storage; - - return (nc->matte_id) ? strlen(nc->matte_id) : 0; + char *matte_id = BKE_cryptomatte_entries_to_matte_id(nc); + int result = strlen(matte_id); + MEM_freeN(matte_id); + return result; } static void rna_NodeCryptomatte_matte_set(PointerRNA *ptr, const char *value) { bNode *node = (bNode *)ptr->data; NodeCryptomatte *nc = node->storage; - - if (nc->matte_id) { - MEM_freeN(nc->matte_id); - } - - if (value && value[0]) { - nc->matte_id = BLI_strdup(value); - } - else { - nc->matte_id = NULL; - } + BKE_cryptomatte_matte_id_to_entries(NULL, nc, value); } static void rna_NodeCryptomatte_update_add(Main *bmain, Scene *scene, PointerRNA *ptr) @@ -4268,7 +4338,7 @@ static void def_math(StructRNA *srna) prop = RNA_def_property(srna, "use_clamp", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom2", SHD_MATH_CLAMP); - RNA_def_property_ui_text(prop, "Clamp", "Clamp result of the node to 0..1 range"); + RNA_def_property_ui_text(prop, "Clamp", "Clamp result of the node to 0.0 to 1.0 range"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } @@ -4387,7 +4457,7 @@ static void def_mix_rgb(StructRNA *srna) prop = RNA_def_property(srna, "use_clamp", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom2", SHD_MIXRGB_CLAMP); - RNA_def_property_ui_text(prop, "Clamp", "Clamp result of the node to 0..1 range"); + RNA_def_property_ui_text(prop, "Clamp", "Clamp result of the node to 0.0 to 1.0 range"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } @@ -4410,6 +4480,19 @@ static void def_texture(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } +static void def_fn_input_vector(StructRNA *srna) +{ + PropertyRNA *prop; + + RNA_def_struct_sdna_from(srna, "NodeInputVector", "storage"); + + prop = RNA_def_property(srna, "vector", PROP_FLOAT, PROP_XYZ); + RNA_def_property_array(prop, 3); + RNA_def_property_float_sdna(prop, NULL, "vector"); + RNA_def_property_ui_text(prop, "Vector", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); +} + /* -- Shader Nodes ---------------------------------------------------------- */ static void def_sh_output(StructRNA *srna) @@ -5139,12 +5222,12 @@ static void def_sh_tex_pointdensity(StructRNA *srna) "PARTICLE_AGE", 0, "Particle Age", - "Lifetime mapped as 0.0 - 1.0 intensity"}, + "Lifetime mapped as 0.0 to 1.0 intensity"}, {SHD_POINTDENSITY_COLOR_PARTSPEED, "PARTICLE_SPEED", 0, "Particle Speed", - "Particle speed (absolute magnitude of velocity) mapped as 0.0-1.0 intensity"}, + "Particle speed (absolute magnitude of velocity) mapped as 0.0 to 1.0 intensity"}, {SHD_POINTDENSITY_COLOR_PARTVEL, "PARTICLE_VELOCITY", 0, @@ -5728,7 +5811,7 @@ static void def_cmp_alpha_over(StructRNA *srna) /* XXX: Tooltip */ prop = RNA_def_property(srna, "use_premultiply", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", 1); - RNA_def_property_ui_text(prop, "Convert Premul", ""); + RNA_def_property_ui_text(prop, "Convert Premultiplied", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "NodeTwoFloats", "storage"); @@ -5736,7 +5819,7 @@ static void def_cmp_alpha_over(StructRNA *srna) prop = RNA_def_property(srna, "premul", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "x"); RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_ui_text(prop, "Premul", "Mix Factor"); + RNA_def_property_ui_text(prop, "Premultiplied", "Mix Factor"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } @@ -5899,7 +5982,7 @@ static void def_cmp_map_range(StructRNA *srna) prop = RNA_def_property(srna, "use_clamp", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", 1); - RNA_def_property_ui_text(prop, "Clamp", "Clamp result of the node to 0..1 range"); + RNA_def_property_ui_text(prop, "Clamp", "Clamp result of the node to 0.0 to 1.0 range"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } @@ -6552,7 +6635,7 @@ static void def_cmp_brightcontrast(StructRNA *srna) prop = RNA_def_property(srna, "use_premultiply", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "custom1", 1); - RNA_def_property_ui_text(prop, "Convert Premul", "Keep output image premultiplied alpha"); + RNA_def_property_ui_text(prop, "Convert Premultiplied", "Keep output image premultiplied alpha"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } @@ -6612,7 +6695,7 @@ static void def_cmp_channel_matte(StructRNA *srna) static const EnumPropertyItem algorithm_items[] = { {0, "SINGLE", 0, "Single", "Limit by single channel"}, - {1, "MAX", 0, "Max", "Limit by max of other channels"}, + {1, "MAX", 0, "Max", "Limit by maximum of other channels"}, {0, NULL, 0, NULL, NULL}, }; @@ -6799,8 +6882,8 @@ static void def_cmp_defocus(StructRNA *srna) RNA_def_property_range(prop, 0.0f, 128.0f); RNA_def_property_ui_text( prop, - "F-stop", - "Amount of focal blur, 128=infinity=perfect focus, half the value doubles " + "F-Stop", + "Amount of focal blur, 128 (infinity) is perfect focus, half the value doubles " "the blur radius"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); @@ -6816,7 +6899,7 @@ static void def_cmp_defocus(StructRNA *srna) RNA_def_property_ui_text( prop, "Threshold", - "CoC radius threshold, prevents background bleed on in-focus midground, 0=off"); + "CoC radius threshold, prevents background bleed on in-focus midground, 0 is disabled"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "use_preview", PROP_BOOLEAN, PROP_NONE); @@ -7007,8 +7090,8 @@ static void def_cmp_premul_key(StructRNA *srna) PropertyRNA *prop; static const EnumPropertyItem type_items[] = { - {0, "STRAIGHT_TO_PREMUL", 0, "Straight to Premul", ""}, - {1, "PREMUL_TO_STRAIGHT", 0, "Premul to Straight", ""}, + {0, "STRAIGHT_TO_PREMUL", 0, "To Premultiplied", "Convert straight to premultiplied"}, + {1, "PREMUL_TO_STRAIGHT", 0, "To Straight", "Convert premultiplied to straight"}, {0, NULL, 0, NULL, NULL}, }; @@ -7602,8 +7685,8 @@ static void def_cmp_bokehblur(StructRNA *srna) RNA_def_property_range(prop, 0.0f, 128.0f); RNA_def_property_ui_text( prop, - "F-stop", - "Amount of focal blur, 128=infinity=perfect focus, half the value doubles " + "F-Stop", + "Amount of focal blur, 128 (infinity) is perfect focus, half the value doubles " "the blur radius"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); # endif @@ -8154,7 +8237,7 @@ static void def_cmp_sunbeams(StructRNA *srna) RNA_def_property_range(prop, -100.0f, 100.0f); RNA_def_property_ui_range(prop, -10.0f, 10.0f, 10, 3); RNA_def_property_ui_text( - prop, "Source", "Source point of rays as a factor of the image width & height"); + prop, "Source", "Source point of rays as a factor of the image width and height"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "ray_length", PROP_FLOAT, PROP_UNSIGNED); @@ -8165,6 +8248,24 @@ static void def_cmp_sunbeams(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } +static void def_cmp_cryptomatte_entry(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "CryptomatteEntry", NULL); + RNA_def_struct_sdna(srna, "CryptomatteEntry"); + + prop = RNA_def_property(srna, "encoded_hash", PROP_FLOAT, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_float_sdna(prop, NULL, "encoded_hash"); + + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Name", ""); + RNA_def_struct_name_property(srna, prop); +} + static void def_cmp_cryptomatte(StructRNA *srna) { PropertyRNA *prop; @@ -8336,19 +8437,28 @@ static void def_geo_attribute_create_common(StructRNA *srna, RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } -static void def_geo_random_attribute(StructRNA *srna) +static void def_geo_attribute_randomize(StructRNA *srna) { def_geo_attribute_create_common(srna, "rna_GeometryNodeAttributeRandom_type_itemf", "rna_GeometryNodeAttributeRandom_domain_itemf"); } +static void def_geo_attribute_fill(StructRNA *srna) +{ + def_geo_attribute_create_common(srna, + "rna_GeometryNodeAttributeFill_type_itemf", + "rna_GeometryNodeAttributeFill_domain_itemf"); +} + static void def_geo_attribute_math(StructRNA *srna) { PropertyRNA *prop; + RNA_def_struct_sdna_from(srna, "NodeAttributeMath", "storage"); + prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "custom1"); + RNA_def_property_enum_sdna(prop, NULL, "operation"); RNA_def_property_enum_items(prop, rna_enum_node_math_items); RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeMath_operation_itemf"); RNA_def_property_enum_default(prop, NODE_MATH_ADD); @@ -8356,18 +8466,124 @@ static void def_geo_attribute_math(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "input_type_a", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_bitflag_sdna(prop, NULL, "custom2"); - RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_a_items); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "input_type_a"); + RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float); RNA_def_property_ui_text(prop, "Input Type A", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); prop = RNA_def_property(srna, "input_type_b", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_bitflag_sdna(prop, NULL, "custom2"); - RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_b_items); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "input_type_b"); + RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float); + RNA_def_property_ui_text(prop, "Input Type B", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); +} + +static void def_geo_point_instance(StructRNA *srna) +{ + static const EnumPropertyItem instance_type_items[] = { + {GEO_NODE_POINT_INSTANCE_TYPE_OBJECT, + "OBJECT", + ICON_NONE, + "Object", + "Instance an individual object on all points"}, + {GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION, + "COLLECTION", + ICON_NONE, + "Collection", + "Instance an entire collection on all points"}, + {0, NULL, 0, NULL, NULL}, + }; + + PropertyRNA *prop; + + prop = RNA_def_property(srna, "instance_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "custom1"); + RNA_def_property_enum_items(prop, instance_type_items); + RNA_def_property_enum_default(prop, GEO_NODE_POINT_INSTANCE_TYPE_OBJECT); + RNA_def_property_ui_text(prop, "Instance Type", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); + + prop = RNA_def_property(srna, "use_whole_collection", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "custom2", 1); + RNA_def_property_ui_text(prop, "Whole Collection", "Instance entire collection on each point"); + RNA_def_property_update(prop, 0, "rna_Node_socket_update"); +} + +static void def_geo_attribute_mix(StructRNA *srna) +{ + PropertyRNA *prop; + + RNA_def_struct_sdna_from(srna, "NodeAttributeMix", "storage"); + + prop = RNA_def_property(srna, "blend_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_enum_ramp_blend_items); + RNA_def_property_enum_default(prop, MA_RAMP_BLEND); + RNA_def_property_ui_text(prop, "Blending Mode", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + + prop = RNA_def_property(srna, "input_type_factor", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float); + RNA_def_property_ui_text(prop, "Input Type Factor", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); + + prop = RNA_def_property(srna, "input_type_a", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_no_boolean); + RNA_def_property_ui_text(prop, "Input Type A", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); + + prop = RNA_def_property(srna, "input_type_b", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_no_boolean); + RNA_def_property_ui_text(prop, "Input Type B", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); +} + +static void def_geo_attribute_attribute_compare(StructRNA *srna) +{ + PropertyRNA *prop; + + RNA_def_struct_sdna_from(srna, "NodeAttributeCompare", "storage"); + + prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_enum_node_float_compare_items); + RNA_def_property_enum_default(prop, NODE_MATH_ADD); + RNA_def_property_ui_text(prop, "Operation", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); + + prop = RNA_def_property(srna, "input_type_a", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_any); + RNA_def_property_ui_text(prop, "Input Type A", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); + + prop = RNA_def_property(srna, "input_type_b", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_any); RNA_def_property_ui_text(prop, "Input Type B", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } +static void def_geo_point_distribute(StructRNA *srna) +{ + PropertyRNA *prop; + + prop = RNA_def_property(srna, "distribute_method", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "custom1"); + RNA_def_property_enum_items(prop, rna_node_geometry_point_distribute_method_items); + RNA_def_property_enum_default(prop, GEO_NODE_POINT_DISTRIBUTE_RANDOM); + RNA_def_property_ui_text(prop, "Distribution Method", "Method to use for scattering points"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); +} + +static void def_geo_attribute_color_ramp(StructRNA *srna) +{ + PropertyRNA *prop; + + RNA_def_struct_sdna_from(srna, "NodeAttributeColorRamp", "storage"); + + prop = RNA_def_property(srna, "color_ramp", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "ColorRamp"); + RNA_def_property_ui_text(prop, "Color Ramp", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); +} + /* -------------------------------------------------------------------------- */ static void rna_def_shader_node(BlenderRNA *brna) @@ -8393,6 +8609,8 @@ static void rna_def_compositor_node(BlenderRNA *brna) /* compositor node need_exec flag */ func = RNA_def_function(srna, "tag_need_exec", "rna_CompositorNode_tag_need_exec"); RNA_def_function_ui_description(func, "Tag the node for compositor update"); + + def_cmp_cryptomatte_entry(brna); } static void rna_def_texture_node(BlenderRNA *brna) @@ -9074,6 +9292,41 @@ static void rna_def_node_socket_geometry(BlenderRNA *brna, RNA_def_struct_sdna(srna, "bNodeSocket"); } +static void rna_def_node_socket_collection(BlenderRNA *brna, + const char *identifier, + const char *interface_idname) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, identifier, "NodeSocketStandard"); + RNA_def_struct_ui_text(srna, "Collection Node Socket", "Collection socket of a node"); + RNA_def_struct_sdna(srna, "bNodeSocket"); + + RNA_def_struct_sdna_from(srna, "bNodeSocketValueCollection", "default_value"); + + prop = RNA_def_property(srna, "default_value", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "value"); + RNA_def_property_struct_type(prop, "Collection"); + RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket"); + RNA_def_property_update( + prop, NC_NODE | NA_EDITED, "rna_NodeSocketStandard_value_and_relation_update"); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT | PROP_CONTEXT_UPDATE); + + /* socket interface */ + srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard"); + RNA_def_struct_ui_text(srna, "Collection Node Socket Interface", "Collection socket of a node"); + RNA_def_struct_sdna(srna, "bNodeSocket"); + + RNA_def_struct_sdna_from(srna, "bNodeSocketValueCollection", "default_value"); + + prop = RNA_def_property(srna, "default_value", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "value"); + RNA_def_property_struct_type(prop, "Collection"); + RNA_def_property_ui_text(prop, "Default Value", "Input value used for unconnected socket"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update"); +} + static void rna_def_node_socket_standard_types(BlenderRNA *brna) { /* XXX Workaround: Registered functions are not exposed in python by bpy, @@ -9214,6 +9467,8 @@ static void rna_def_node_socket_standard_types(BlenderRNA *brna) rna_def_node_socket_image(brna, "NodeSocketImage", "NodeSocketInterfaceImage"); rna_def_node_socket_geometry(brna, "NodeSocketGeometry", "NodeSocketInterfaceGeometry"); + + rna_def_node_socket_collection(brna, "NodeSocketCollection", "NodeSocketInterfaceCollection"); } static void rna_def_internal_node(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index ee115b74379..3e8d8e10b37 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -579,7 +579,11 @@ static StructRNA *rna_Object_data_typef(PointerRNA *ptr) return &RNA_ID; # endif case OB_POINTCLOUD: +# ifdef WITH_POINT_CLOUD return &RNA_PointCloud; +# else + return &RNA_ID; +# endif case OB_VOLUME: return &RNA_Volume; default: @@ -2751,8 +2755,8 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Track Axis", - "Axis that points in 'forward' direction (applies to InstanceFrame when " - "parent 'Follow' is enabled)"); + "Axis that points in the 'forward' direction (applies to Instance Vertices when " + "Align to Vertex Normal is enabled)"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_internal_update"); prop = RNA_def_property(srna, "up_axis", PROP_ENUM, PROP_NONE); @@ -2761,8 +2765,8 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Up Axis", - "Axis that points in the upward direction (applies to InstanceFrame when " - "parent 'Follow' is enabled)"); + "Axis that points in the upward direction (applies to Instance Vertices when " + "Align to Vertex Normal is enabled)"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_internal_update"); /* proxy */ diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c index 39783f9e31f..12fd2b78d91 100644 --- a/source/blender/makesrna/intern/rna_object_force.c +++ b/source/blender/makesrna/intern/rna_object_force.c @@ -21,6 +21,7 @@ #include <stdlib.h> #include "DNA_cloth_types.h" +#include "DNA_dynamicpaint_types.h" #include "DNA_fluid_types.h" #include "DNA_object_force_types.h" #include "DNA_object_types.h" @@ -154,7 +155,7 @@ static char *rna_PointCache_path(PointerRNA *ptr) } char name_esc[sizeof(md->name) * 2]; - BLI_strescape(name_esc, md->name, sizeof(name_esc)); + BLI_str_escape(name_esc, md->name, sizeof(name_esc)); switch (md->type) { case eModifierType_ParticleSystem: { @@ -171,7 +172,7 @@ static char *rna_PointCache_path(PointerRNA *ptr) for (; surface; surface = surface->next) { if (surface->pointcache == cache) { char name_surface_esc[sizeof(surface->name) * 2]; - BLI_strescape(name_surface_esc, surface->name, sizeof(name_surface_esc)); + BLI_str_escape(name_surface_esc, surface->name, sizeof(name_surface_esc)); return BLI_sprintfN( "modifiers[\"%s\"].canvas_settings.canvas_surfaces[\"%s\"].point_cache", name_esc, @@ -436,7 +437,7 @@ static char *rna_CollisionSettings_path(PointerRNA *UNUSED(ptr)) if (md) { char name_esc[sizeof(md->name) * 2]; - BLI_strescape(name_esc, md->name, sizeof(name_esc)); + BLI_str_escape(name_esc, md->name, sizeof(name_esc)); return BLI_sprintfN("modifiers[\"%s\"].settings", name_esc); } else { @@ -608,7 +609,7 @@ static char *rna_SoftBodySettings_path(PointerRNA *ptr) ModifierData *md = (ModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Softbody); char name_esc[sizeof(md->name) * 2]; - BLI_strescape(name_esc, md->name, sizeof(name_esc)); + BLI_str_escape(name_esc, md->name, sizeof(name_esc)); return BLI_sprintfN("modifiers[\"%s\"].settings", name_esc); } @@ -797,7 +798,7 @@ static char *rna_EffectorWeight_path(PointerRNA *ptr) /* no pointer from modifier data to actual softbody storage, would be good to add */ if (ob->soft->effector_weights == ew) { char name_esc[sizeof(md->name) * 2]; - BLI_strescape(name_esc, md->name, sizeof(name_esc)); + BLI_str_escape(name_esc, md->name, sizeof(name_esc)); return BLI_sprintfN("modifiers[\"%s\"].settings.effector_weights", name_esc); } } @@ -808,7 +809,7 @@ static char *rna_EffectorWeight_path(PointerRNA *ptr) ClothModifierData *cmd = (ClothModifierData *)md; if (cmd->sim_parms->effector_weights == ew) { char name_esc[sizeof(md->name) * 2]; - BLI_strescape(name_esc, md->name, sizeof(name_esc)); + BLI_str_escape(name_esc, md->name, sizeof(name_esc)); return BLI_sprintfN("modifiers[\"%s\"].settings.effector_weights", name_esc); } } @@ -820,7 +821,7 @@ static char *rna_EffectorWeight_path(PointerRNA *ptr) if (fmd->type == MOD_FLUID_TYPE_DOMAIN && fmd->domain && fmd->domain->effector_weights == ew) { char name_esc[sizeof(md->name) * 2]; - BLI_strescape(name_esc, md->name, sizeof(name_esc)); + BLI_str_escape(name_esc, md->name, sizeof(name_esc)); return BLI_sprintfN("modifiers[\"%s\"].domain_settings.effector_weights", name_esc); } } @@ -838,8 +839,8 @@ static char *rna_EffectorWeight_path(PointerRNA *ptr) char name_esc[sizeof(md->name) * 2]; char name_esc_surface[sizeof(surface->name) * 2]; - BLI_strescape(name_esc, md->name, sizeof(name_esc)); - BLI_strescape(name_esc_surface, surface->name, sizeof(name_esc_surface)); + BLI_str_escape(name_esc, md->name, sizeof(name_esc)); + BLI_str_escape(name_esc_surface, surface->name, sizeof(name_esc_surface)); return BLI_sprintfN( "modifiers[\"%s\"].canvas_settings.canvas_surfaces[\"%s\"]" ".effector_weights", @@ -1486,10 +1487,11 @@ static void rna_def_field(BlenderRNA *brna) prop = RNA_def_property(srna, "texture_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "tex_mode"); RNA_def_property_enum_items(prop, texture_items); - RNA_def_property_ui_text(prop, - "Texture Mode", - "How the texture effect is calculated (RGB & Curl need a RGB texture, " - "else Gradient will be used instead)"); + RNA_def_property_ui_text( + prop, + "Texture Mode", + "How the texture effect is calculated (RGB and Curl need a RGB texture, " + "else Gradient will be used instead)"); RNA_def_property_update(prop, 0, "rna_FieldSettings_update"); prop = RNA_def_property(srna, "z_direction", PROP_ENUM, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index 5987f52328d..3e40d382237 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -1490,7 +1490,7 @@ static char *rna_ParticleSystem_path(PointerRNA *ptr) ParticleSystem *psys = (ParticleSystem *)ptr->data; char name_esc[sizeof(psys->name) * 2]; - BLI_strescape(name_esc, psys->name, sizeof(name_esc)); + BLI_str_escape(name_esc, psys->name, sizeof(name_esc)); return BLI_sprintfN("particle_systems[\"%s\"]", name_esc); } @@ -2484,7 +2484,7 @@ static void rna_def_particle_settings(BlenderRNA *brna) NULL, "ParticleSettingsTextureSlot", "ParticleSettingsTextureSlots", - "rna_Particle_reset", + "rna_Particle_reset_dependency", NULL); /* Fluid particle type can't be checked from the type value in RNA @@ -2948,7 +2948,7 @@ static void rna_def_particle_settings(BlenderRNA *brna) prop, "Adaptive Subframe Threshold", "The relative distance a particle can move before requiring more subframes " - "(target Courant number); 0.01-0.3 is the recommended range"); + "(target Courant number); 0.01 to 0.3 is the recommended range"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); prop = RNA_def_property(srna, "jitter_factor", PROP_FLOAT, PROP_NONE); @@ -3298,48 +3298,48 @@ static void rna_def_particle_settings(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "rough1"); RNA_def_property_range(prop, 0.0f, 100000.0f); RNA_def_property_ui_range(prop, 0.0f, 10.0f, 0.1, 3); - RNA_def_property_ui_text(prop, "Rough1", "Amount of location dependent rough"); + RNA_def_property_ui_text(prop, "Roughness 1", "Amount of location dependent roughness"); RNA_def_property_update(prop, 0, "rna_Particle_redo_child"); prop = RNA_def_property(srna, "roughness_1_size", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "rough1_size"); RNA_def_property_range(prop, 0.01f, 100000.0f); RNA_def_property_ui_range(prop, 0.01f, 10.0f, 0.1, 3); - RNA_def_property_ui_text(prop, "Size1", "Size of location dependent rough"); + RNA_def_property_ui_text(prop, "Size 1", "Size of location dependent roughness"); RNA_def_property_update(prop, 0, "rna_Particle_redo_child"); prop = RNA_def_property(srna, "roughness_2", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "rough2"); RNA_def_property_range(prop, 0.0f, 100000.0f); RNA_def_property_ui_range(prop, 0.0f, 10.0f, 0.1, 3); - RNA_def_property_ui_text(prop, "Rough2", "Amount of random rough"); + RNA_def_property_ui_text(prop, "Roughness 2", "Amount of random roughness"); RNA_def_property_update(prop, 0, "rna_Particle_redo_child"); prop = RNA_def_property(srna, "roughness_2_size", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "rough2_size"); RNA_def_property_range(prop, 0.01f, 100000.0f); RNA_def_property_ui_range(prop, 0.01f, 10.0f, 0.1, 3); - RNA_def_property_ui_text(prop, "Size2", "Size of random rough"); + RNA_def_property_ui_text(prop, "Size 2", "Size of random roughness"); RNA_def_property_update(prop, 0, "rna_Particle_redo_child"); prop = RNA_def_property(srna, "roughness_2_threshold", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "rough2_thres"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text( - prop, "Threshold", "Amount of particles left untouched by random rough"); + prop, "Threshold", "Amount of particles left untouched by random roughness"); RNA_def_property_update(prop, 0, "rna_Particle_redo_child"); prop = RNA_def_property(srna, "roughness_endpoint", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "rough_end"); RNA_def_property_range(prop, 0.0f, 100000.0f); RNA_def_property_ui_range(prop, 0.0f, 10.0f, 0.1, 3); - RNA_def_property_ui_text(prop, "Rough Endpoint", "Amount of end point rough"); + RNA_def_property_ui_text(prop, "Roughness Endpoint", "Amount of endpoint roughness"); RNA_def_property_update(prop, 0, "rna_Particle_redo_child"); prop = RNA_def_property(srna, "roughness_end_shape", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "rough_end_shape"); RNA_def_property_range(prop, 0.0f, 10.0f); - RNA_def_property_ui_text(prop, "Shape", "Shape of end point rough"); + RNA_def_property_ui_text(prop, "Shape", "Shape of endpoint roughness"); RNA_def_property_update(prop, 0, "rna_Particle_redo_child"); prop = RNA_def_property(srna, "use_roughness_curve", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c index bc9aabbefe6..aad94f4729f 100644 --- a/source/blender/makesrna/intern/rna_pose.c +++ b/source/blender/makesrna/intern/rna_pose.c @@ -132,7 +132,7 @@ static char *rna_PoseBone_path(PointerRNA *ptr) bPoseChannel *pchan = ptr->data; char name_esc[sizeof(pchan->name) * 2]; - BLI_strescape(name_esc, pchan->name, sizeof(name_esc)); + BLI_str_escape(name_esc, pchan->name, sizeof(name_esc)); return BLI_sprintfN("pose.bones[\"%s\"]", name_esc); } @@ -1383,7 +1383,7 @@ static void rna_def_pose_channel(BlenderRNA *brna) "rna_PoseChannel_bone_group_index_set", "rna_PoseChannel_bone_group_index_range"); RNA_def_property_ui_text( - prop, "Bone Group Index", "Bone Group this pose channel belongs to (0=no group)"); + prop, "Bone Group Index", "Bone group this pose channel belongs to (0 means no group)"); RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable"); RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update"); @@ -1551,14 +1551,13 @@ static void rna_def_pose_itasc(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Feedback", - "Feedback coefficient for error correction, average response time is 1/feedback " - "(default=20)"); + "Feedback coefficient for error correction, average response time is 1/feedback"); RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Itasc_update"); prop = RNA_def_property(srna, "velocity_max", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "maxvel"); RNA_def_property_range(prop, 0.0f, 100.0f); - RNA_def_property_ui_text(prop, "Max Velocity", "Maximum joint velocity in rad/s (default=50)"); + RNA_def_property_ui_text(prop, "Max Velocity", "Maximum joint velocity in radians/second"); RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Itasc_update"); prop = RNA_def_property(srna, "solver", PROP_ENUM, PROP_NONE); @@ -1574,7 +1573,7 @@ static void rna_def_pose_itasc(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Damp", "Maximum damping coefficient when singular value is nearly 0 " - "(higher values=more stability, less reactivity - default=0.5)"); + "(higher values produce results with more stability, less reactivity)"); RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Itasc_update"); prop = RNA_def_property(srna, "damping_epsilon", PROP_FLOAT, PROP_FACTOR); @@ -1583,7 +1582,7 @@ static void rna_def_pose_itasc(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Epsilon", "Singular value under which damping is progressively applied " - "(higher values=more stability, less reactivity - default=0.1)"); + "(higher values produce results with more stability, less reactivity)"); RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Itasc_update"); } diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index eae1c7bc223..e2001eacf4c 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -1360,7 +1360,7 @@ static int rna_property_override_diff_propptr(Main *bmain, BLI_assert(STREQ(rna_itemname_a, rna_itemname_b)); char esc_item_name[RNA_PATH_BUFFSIZE]; - const size_t esc_item_name_len = BLI_strescape( + const size_t esc_item_name_len = BLI_str_escape( esc_item_name, rna_itemname_a, RNA_PATH_BUFFSIZE); extended_rna_path_len = rna_path_len + 2 + esc_item_name_len + 2; if (extended_rna_path_len >= RNA_PATH_BUFFSIZE) { @@ -1858,7 +1858,7 @@ int rna_property_override_diff_default(Main *bmain, is_id, is_valid_for_diffing, is_valid_for_insertion, - (RNA_property_override_flag(prop_a) & PROPOVERRIDE_LIBRARY_INSERTION) != 0, + use_collection_insertion, do_create); } # endif @@ -3076,7 +3076,7 @@ static void rna_def_string_property(StructRNA *srna) RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_string_funcs( prop, "rna_StringProperty_default_get", "rna_StringProperty_default_length", NULL); - RNA_def_property_ui_text(prop, "Default", "string default value"); + RNA_def_property_ui_text(prop, "Default", "String default value"); prop = RNA_def_property(srna, "length_max", PROP_INT, PROP_UNSIGNED); RNA_def_property_clear_flag(prop, PROP_EDITABLE); diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 08b3d4f210e..b93922e46f2 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -390,7 +390,7 @@ const EnumPropertyItem rna_enum_image_color_mode_items[] = { "BW", 0, "BW", - "Images get saved in 8 bits grayscale (only PNG, JPEG, TGA, TIF)"}, + "Images get saved in 8-bit grayscale (only PNG, JPEG, TGA, TIF)"}, {R_IMF_PLANES_RGB, "RGB", 0, "RGB", "Images are saved with RGB (color) data"}, {R_IMF_PLANES_RGBA, "RGBA", @@ -408,12 +408,12 @@ const EnumPropertyItem rna_enum_image_color_mode_items[] = { const EnumPropertyItem rna_enum_image_color_depth_items[] = { /* 1 (monochrome) not used */ - {R_IMF_CHAN_DEPTH_8, "8", 0, "8", "8 bit color channels"}, - {R_IMF_CHAN_DEPTH_10, "10", 0, "10", "10 bit color channels"}, - {R_IMF_CHAN_DEPTH_12, "12", 0, "12", "12 bit color channels"}, - {R_IMF_CHAN_DEPTH_16, "16", 0, "16", "16 bit color channels"}, + {R_IMF_CHAN_DEPTH_8, "8", 0, "8", "8-bit color channels"}, + {R_IMF_CHAN_DEPTH_10, "10", 0, "10", "10-bit color channels"}, + {R_IMF_CHAN_DEPTH_12, "12", 0, "12", "12-bit color channels"}, + {R_IMF_CHAN_DEPTH_16, "16", 0, "16", "16-bit color channels"}, /* 24 not used */ - {R_IMF_CHAN_DEPTH_32, "32", 0, "32", "32 bit color channels"}, + {R_IMF_CHAN_DEPTH_32, "32", 0, "32", "32-bit color channels"}, {0, NULL, 0, NULL, NULL}, }; @@ -529,7 +529,7 @@ const EnumPropertyItem rna_enum_bake_pass_filter_type_items[] = { {0, NULL, 0, NULL, NULL}, }; -const EnumPropertyItem rna_enum_view_layer_aov_type_items[] = { +static const EnumPropertyItem rna_enum_view_layer_aov_type_items[] = { {AOV_TYPE_COLOR, "COLOR", 0, "Color", ""}, {AOV_TYPE_VALUE, "VALUE", 0, "Value", ""}, {0, NULL, 0, NULL, NULL}, @@ -699,7 +699,9 @@ const EnumPropertyItem rna_enum_transform_orientation_items[] = { # include "DEG_depsgraph_build.h" # include "DEG_depsgraph_query.h" +# include "SEQ_relations.h" # include "SEQ_sequencer.h" +# include "SEQ_sound.h" # ifdef WITH_FREESTYLE # include "FRS_freestyle.h" @@ -916,7 +918,7 @@ static void rna_Scene_fps_update(Main *bmain, Scene *scene, PointerRNA *UNUSED(p /* NOTE: Tag via dependency graph will take care of all the updates ion the evaluated domain, * however, changes in FPS actually modifies an original skip length, * so this we take care about here. */ - BKE_sequencer_refresh_sound_length(bmain, scene); + SEQ_sound_update_length(bmain, scene); } static void rna_Scene_listener_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr)) @@ -1812,7 +1814,9 @@ void rna_ViewLayer_pass_update(Main *bmain, Scene *activescene, PointerRNA *ptr) static char *rna_SceneRenderView_path(PointerRNA *ptr) { SceneRenderView *srv = (SceneRenderView *)ptr->data; - return BLI_sprintfN("render.views[\"%s\"]", srv->name); + char srv_name_esc[sizeof(srv->name) * 2]; + BLI_str_escape(srv_name_esc, srv->name, sizeof(srv_name_esc)); + return BLI_sprintfN("render.views[\"%s\"]", srv_name_esc); } static void rna_Scene_use_nodes_update(bContext *C, PointerRNA *ptr) @@ -2198,6 +2202,11 @@ static char *rna_CurvePaintSettings_path(PointerRNA *UNUSED(ptr)) return BLI_strdup("tool_settings.curve_paint_settings"); } +static char *rna_SequencerToolSettings_path(PointerRNA *UNUSED(ptr)) +{ + return BLI_strdup("tool_settings.sequencer_tool_settings"); +} + /* generic function to recalc geometry */ static void rna_EditMesh_update(bContext *C, PointerRNA *UNUSED(ptr)) { @@ -2243,7 +2252,7 @@ static void rna_SceneCamera_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Po Scene *scene = (Scene *)ptr->owner_id; Object *camera = scene->camera; - BKE_sequencer_cache_cleanup(scene); + SEQ_cache_cleanup(scene); if (camera && (camera->type == OB_CAMERA)) { DEG_id_tag_update(&camera->id, ID_RECALC_GEOMETRY); @@ -2252,7 +2261,7 @@ static void rna_SceneCamera_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Po static void rna_SceneSequencer_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr)) { - BKE_sequencer_cache_cleanup(scene); + SEQ_cache_cleanup(scene); } static char *rna_ToolSettings_path(PointerRNA *UNUSED(ptr)) @@ -3582,6 +3591,38 @@ static void rna_def_tool_settings(BlenderRNA *brna) RNA_def_property_pointer_sdna(prop, NULL, "custom_bevel_profile_preset"); RNA_def_property_struct_type(prop, "CurveProfile"); RNA_def_property_ui_text(prop, "Curve Profile Widget", "Used for defining a profile's path"); + + /* Sequencer tool settings */ + prop = RNA_def_property(srna, "sequencer_tool_settings", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); + RNA_def_property_struct_type(prop, "SequencerToolSettings"); + RNA_def_property_ui_text(prop, "Sequencer Tool Settings", NULL); +} + +static void rna_def_sequencer_tool_settings(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + static const EnumPropertyItem scale_fit_methods[] = { + {SEQ_SCALE_TO_FIT, "FIT", 0, "Scale to Fit", "Scale image to fit within the canvas"}, + {SEQ_SCALE_TO_FILL, "FILL", 0, "Scale to Fill", "Scale image to completely fill the canvas"}, + {SEQ_STRETCH_TO_FILL, "STRETCH", 0, "Stretch to Fill", "Stretch image to fill the canvas"}, + {SEQ_USE_ORIGINAL_SIZE, + "ORIGINAL", + 0, + "Use Original Size", + "Keep image at its original size"}, + {0, NULL, 0, NULL, NULL}, + }; + + srna = RNA_def_struct(brna, "SequencerToolSettings", NULL); + RNA_def_struct_path_func(srna, "rna_SequencerToolSettings_path"); + RNA_def_struct_ui_text(srna, "Sequencer Tool Settings", ""); + + prop = RNA_def_property(srna, "fit_method", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, scale_fit_methods); + RNA_def_property_ui_text(prop, "Fit Method", "Scale fit method"); } static void rna_def_unified_paint_settings(BlenderRNA *brna) @@ -3993,17 +4034,11 @@ static void rna_def_view_layer_eevee(BlenderRNA *brna) StructRNA *srna; PropertyRNA *prop; srna = RNA_def_struct(brna, "ViewLayerEEVEE", NULL); - RNA_def_struct_ui_text(srna, "EEVEE Settings", "View layer settings for EEVEE"); - - prop = RNA_def_property(srna, "use_pass_volume_scatter", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "render_passes", EEVEE_RENDER_PASS_VOLUME_SCATTER); - RNA_def_property_ui_text(prop, "Volume Scatter", "Deliver volume scattering pass"); - RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update"); + RNA_def_struct_ui_text(srna, "Eevee Settings", "View layer settings for Eevee"); - prop = RNA_def_property(srna, "use_pass_volume_transmittance", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna( - prop, NULL, "render_passes", EEVEE_RENDER_PASS_VOLUME_TRANSMITTANCE); - RNA_def_property_ui_text(prop, "Volume Transmittance", "Deliver volume transmittance pass"); + prop = RNA_def_property(srna, "use_pass_volume_direct", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "render_passes", EEVEE_RENDER_PASS_VOLUME_LIGHT); + RNA_def_property_ui_text(prop, "Volume Light", "Deliver volume direct light pass"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update"); prop = RNA_def_property(srna, "use_pass_bloom", PROP_BOOLEAN, PROP_NONE); @@ -4088,7 +4123,7 @@ void rna_def_view_layer_common(StructRNA *srna, const bool scene) prop = RNA_def_property(srna, "eevee", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_struct_type(prop, "ViewLayerEEVEE"); - RNA_def_property_ui_text(prop, "EEVEE Settings", "View layer settings for EEVEE"); + RNA_def_property_ui_text(prop, "Eevee Settings", "View layer settings for Eevee"); prop = RNA_def_property(srna, "aovs", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "aovs", NULL); @@ -4207,7 +4242,7 @@ void rna_def_view_layer_common(StructRNA *srna, const bool scene) prop = RNA_def_property(srna, "use_ztransp", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "layflag", SCE_LAY_ZTRA); RNA_def_property_ui_text( - prop, "ZTransp", "Render Z-Transparent faces in this Layer (on top of Solid and Halos)"); + prop, "Z-Transparent", "Render Z-transparent faces in this layer (on top of Solid and Halos)"); if (scene) { RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); } @@ -4319,7 +4354,7 @@ void rna_def_view_layer_common(StructRNA *srna, const bool scene) prop = RNA_def_property(srna, "use_pass_mist", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_MIST); - RNA_def_property_ui_text(prop, "Mist", "Deliver mist factor pass (0.0-1.0)"); + RNA_def_property_ui_text(prop, "Mist", "Deliver mist factor pass (0.0 to 1.0)"); if (scene) { RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_ViewLayer_pass_update"); } @@ -5487,7 +5522,7 @@ static void rna_def_scene_image_format_data(BlenderRNA *brna) prop = RNA_def_property(srna, "use_zbuffer", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", R_IMF_FLAG_ZBUF); RNA_def_property_ui_text( - prop, "Z Buffer", "Save the z-depth per pixel (32 bit unsigned int z-buffer)"); + prop, "Z Buffer", "Save the z-depth per pixel (32-bit unsigned integer z-buffer)"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "use_preview", PROP_BOOLEAN, PROP_NONE); @@ -5723,26 +5758,26 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna) prop = RNA_def_property(srna, "video_bitrate", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "video_bitrate"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_ui_text(prop, "Bitrate", "Video bitrate (kb/s)"); + RNA_def_property_ui_text(prop, "Bitrate", "Video bitrate (kbit/s)"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "minrate", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "rc_min_rate"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_ui_text(prop, "Min Rate", "Rate control: min rate (kb/s)"); + RNA_def_property_ui_text(prop, "Min Rate", "Rate control: min rate (kbit/s)"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "maxrate", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "rc_max_rate"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_ui_text(prop, "Max Rate", "Rate control: max rate (kb/s)"); + RNA_def_property_ui_text(prop, "Max Rate", "Rate control: max rate (kbit/s)"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "muxrate", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "mux_rate"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_range(prop, 0, 100000000); - RNA_def_property_ui_text(prop, "Mux Rate", "Mux rate (bits/s(!))"); + RNA_def_property_ui_text(prop, "Mux Rate", "Mux rate (bits/second)"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); prop = RNA_def_property(srna, "gopsize", PROP_INT, PROP_NONE); @@ -6366,7 +6401,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_range(prop, 0.0, 1000.0); RNA_def_property_ui_text(prop, "Scale", - "Instead of automatically normalizing to 0..1, " + "Instead of automatically normalizing to the range 0 to 1, " "apply a user scale to the derivative map"); /* stamp */ @@ -7423,7 +7458,7 @@ static void rna_def_scene_eevee(BlenderRNA *brna) prop = RNA_def_property(srna, "use_shadow_high_bitdepth", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_SHADOW_HIGH_BITDEPTH); - RNA_def_property_ui_text(prop, "High Bitdepth", "Use 32bit shadows"); + RNA_def_property_ui_text(prop, "High Bit Depth", "Use 32-bit shadows"); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); @@ -7958,7 +7993,7 @@ void RNA_def_scene(BlenderRNA *brna) /* EEVEE */ prop = RNA_def_property(srna, "eevee", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "SceneEEVEE"); - RNA_def_property_ui_text(prop, "EEVEE", "EEVEE settings for the scene"); + RNA_def_property_ui_text(prop, "Eevee", "Eevee settings for the scene"); /* Grease Pencil */ prop = RNA_def_property(srna, "grease_pencil_settings", PROP_POINTER, PROP_NONE); @@ -7972,6 +8007,7 @@ void RNA_def_scene(BlenderRNA *brna) rna_def_gpencil_interpolate(brna); rna_def_unified_paint_settings(brna); rna_def_curve_paint_settings(brna); + rna_def_sequencer_tool_settings(brna); rna_def_statvis(brna); rna_def_unit_settings(brna); rna_def_scene_image_format_data(brna); diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c index a57c1196f6a..0549fc8bab2 100644 --- a/source/blender/makesrna/intern/rna_scene_api.c +++ b/source/blender/makesrna/intern/rna_scene_api.c @@ -186,7 +186,7 @@ static void rna_Scene_ray_cast(Scene *scene, static void rna_Scene_sequencer_editing_free(Scene *scene) { - BKE_sequencer_editing_free(scene, true); + SEQ_editing_free(scene, true); } # ifdef WITH_ALEMBIC @@ -343,7 +343,7 @@ void RNA_api_scene(StructRNA *srna) RNA_def_function_output(func, parm); /* Sequencer. */ - func = RNA_def_function(srna, "sequence_editor_create", "BKE_sequencer_editing_ensure"); + func = RNA_def_function(srna, "sequence_editor_create", "SEQ_editing_ensure"); RNA_def_function_ui_description(func, "Ensure sequence editor is valid in this scene"); parm = RNA_def_pointer( func, "sequence_editor", "SequenceEditor", "", "New sequence editor data or NULL"); diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c index ab84dcb0aba..784172b3ac9 100644 --- a/source/blender/makesrna/intern/rna_screen.c +++ b/source/blender/makesrna/intern/rna_screen.c @@ -270,6 +270,8 @@ static void rna_Area_ui_type_update(bContext *C, PointerRNA *ptr) st->space_subtype_set(area, area->butspacetype_subtype); } area->butspacetype_subtype = 0; + + ED_area_tag_refresh(area); } static void rna_View2D_region_to_view(struct View2D *v2d, float x, float y, float result[2]) @@ -586,7 +588,7 @@ static void rna_def_screen(BlenderRNA *brna) prop = RNA_def_property(srna, "show_statusbar", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SCREEN_COLLAPSE_STATUSBAR); - RNA_def_property_ui_text(prop, "Show Status Bar", "Show Status Bar"); + RNA_def_property_ui_text(prop, "Show Status Bar", "Show status bar"); RNA_def_property_update(prop, 0, "rna_Screen_bar_update"); func = RNA_def_function(srna, "statusbar_info", "rna_Screen_statusbar_info_get"); diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index 4313b468deb..eed976c8df1 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -46,7 +46,18 @@ #include "rna_internal.h" +#include "SEQ_add.h" +#include "SEQ_effects.h" +#include "SEQ_iterator.h" +#include "SEQ_modifier.h" +#include "SEQ_prefetch.h" +#include "SEQ_proxy.h" +#include "SEQ_relations.h" #include "SEQ_sequencer.h" +#include "SEQ_sound.h" +#include "SEQ_time.h" +#include "SEQ_transform.h" +#include "SEQ_utils.h" #include "WM_types.h" @@ -103,16 +114,16 @@ static void meta_tmp_ref(Sequence *seq_par, Sequence *seq) static void rna_SequenceElement_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { Scene *scene = (Scene *)ptr->owner_id; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (ed) { StripElem *se = (StripElem *)ptr->data; Sequence *seq; /* slow but we can't avoid! */ - seq = BKE_sequencer_from_elem(&ed->seqbase, se); + seq = SEQ_sequence_from_strip_elem(&ed->seqbase, se); if (seq) { - BKE_sequence_invalidate_cache_raw(scene, seq); + SEQ_relations_invalidate_cache_raw(scene, seq); } } } @@ -122,12 +133,12 @@ static void rna_Sequence_invalidate_raw_update(Main *UNUSED(bmain), PointerRNA *ptr) { Scene *scene = (Scene *)ptr->owner_id; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (ed) { Sequence *seq = (Sequence *)ptr->data; - BKE_sequence_invalidate_cache_raw(scene, seq); + SEQ_relations_invalidate_cache_raw(scene, seq); } } @@ -136,12 +147,12 @@ static void rna_Sequence_invalidate_preprocessed_update(Main *UNUSED(bmain), PointerRNA *ptr) { Scene *scene = (Scene *)ptr->owner_id; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (ed) { Sequence *seq = (Sequence *)ptr->data; - BKE_sequence_invalidate_cache_preprocessed(scene, seq); + SEQ_relations_invalidate_cache_preprocessed(scene, seq); } } @@ -150,12 +161,12 @@ static void rna_Sequence_invalidate_composite_update(Main *UNUSED(bmain), PointerRNA *ptr) { Scene *scene = (Scene *)ptr->owner_id; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (ed) { Sequence *seq = (Sequence *)ptr->data; - BKE_sequence_invalidate_cache_composite(scene, seq); + SEQ_relations_invalidate_cache_composite(scene, seq); } } @@ -172,7 +183,7 @@ static void rna_Sequence_use_sequence(Main *bmain, Scene *scene, PointerRNA *ptr rna_Sequence_invalidate_raw_update(bmain, scene, ptr); /* Changing recursion changes set of IDs which needs to be remapped by the copy-on-write. * the only way for this currently is to tag the ID for ID_RECALC_COPY_ON_WRITE. */ - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (ed) { Sequence *seq = (Sequence *)ptr->data; if (seq->scene != NULL) { @@ -189,7 +200,7 @@ static void rna_SequenceEditor_sequences_all_begin(CollectionPropertyIterator *i PointerRNA *ptr) { Scene *scene = (Scene *)ptr->owner_id; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); meta_tmp_ref(NULL, ed->seqbase.first); @@ -202,8 +213,8 @@ static void rna_SequenceEditor_update_cache(Main *UNUSED(bmain), { Editing *ed = scene->ed; - BKE_sequencer_free_imbuf(scene, &ed->seqbase, false); - BKE_sequencer_cache_cleanup(scene); + SEQ_relations_free_imbuf(scene, &ed->seqbase, false); + SEQ_cache_cleanup(scene); } static void rna_SequenceEditor_sequences_all_next(CollectionPropertyIterator *iter) @@ -263,10 +274,10 @@ static void rna_Sequence_views_format_update(Main *bmain, Scene *scene, PointerR static void do_sequence_frame_change_update(Scene *scene, Sequence *seq) { - Editing *ed = BKE_sequencer_editing_get(scene, false); - ListBase *seqbase = BKE_sequence_seqbase(&ed->seqbase, seq); + Editing *ed = SEQ_editing_get(scene, false); + ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seq); Sequence *tseq; - BKE_sequence_calc_disp(scene, seq); + SEQ_time_update_sequence_bounds(scene, seq); /* ensure effects are always fit in length to their input */ @@ -275,14 +286,14 @@ static void do_sequence_frame_change_update(Scene *scene, Sequence *seq) */ for (tseq = seqbase->first; tseq; tseq = tseq->next) { if (tseq->seq1 || tseq->seq2 || tseq->seq3) { - BKE_sequence_calc(scene, tseq); + SEQ_time_update_sequence(scene, tseq); } } - if (BKE_sequence_test_overlap(seqbase, seq)) { - BKE_sequence_base_shuffle(seqbase, seq, scene); /* XXX - BROKEN!, uses context seqbasep */ + if (SEQ_transform_test_overlap(seqbase, seq)) { + SEQ_transform_seqbase_shuffle(seqbase, seq, scene); /* XXX - BROKEN!, uses context seqbasep */ } - BKE_sequencer_sort(scene); + SEQ_sort(scene); } /* A simple wrapper around above func, directly usable as prop update func. @@ -301,10 +312,10 @@ static void rna_Sequence_start_frame_set(PointerRNA *ptr, int value) Sequence *seq = (Sequence *)ptr->data; Scene *scene = (Scene *)ptr->owner_id; - BKE_sequence_invalidate_cache_composite(scene, seq); - BKE_sequence_translate(scene, seq, value - seq->start); + SEQ_relations_invalidate_cache_composite(scene, seq); + SEQ_transform_translate_sequence(scene, seq, value - seq->start); do_sequence_frame_change_update(scene, seq); - BKE_sequence_invalidate_cache_composite(scene, seq); + SEQ_relations_invalidate_cache_composite(scene, seq); } static void rna_Sequence_start_frame_final_set(PointerRNA *ptr, int value) @@ -312,11 +323,11 @@ static void rna_Sequence_start_frame_final_set(PointerRNA *ptr, int value) Sequence *seq = (Sequence *)ptr->data; Scene *scene = (Scene *)ptr->owner_id; - BKE_sequence_invalidate_cache_composite(scene, seq); - BKE_sequence_tx_set_final_left(seq, value); - BKE_sequence_single_fix(seq); + SEQ_relations_invalidate_cache_composite(scene, seq); + SEQ_transform_set_left_handle_frame(seq, value); + SEQ_transform_fix_single_image_seq_offsets(seq); do_sequence_frame_change_update(scene, seq); - BKE_sequence_invalidate_cache_composite(scene, seq); + SEQ_relations_invalidate_cache_composite(scene, seq); } static void rna_Sequence_end_frame_final_set(PointerRNA *ptr, int value) @@ -324,11 +335,11 @@ static void rna_Sequence_end_frame_final_set(PointerRNA *ptr, int value) Sequence *seq = (Sequence *)ptr->data; Scene *scene = (Scene *)ptr->owner_id; - BKE_sequence_invalidate_cache_composite(scene, seq); - BKE_sequence_tx_set_final_right(seq, value); - BKE_sequence_single_fix(seq); + SEQ_relations_invalidate_cache_composite(scene, seq); + SEQ_transform_set_right_handle_frame(seq, value); + SEQ_transform_fix_single_image_seq_offsets(seq); do_sequence_frame_change_update(scene, seq); - BKE_sequence_invalidate_cache_composite(scene, seq); + SEQ_relations_invalidate_cache_composite(scene, seq); } static void rna_Sequence_frame_offset_start_set(PointerRNA *ptr, int value) @@ -336,7 +347,7 @@ static void rna_Sequence_frame_offset_start_set(PointerRNA *ptr, int value) Sequence *seq = (Sequence *)ptr->data; Scene *scene = (Scene *)ptr->owner_id; - BKE_sequence_invalidate_cache_composite(scene, seq); + SEQ_relations_invalidate_cache_composite(scene, seq); seq->startofs = value; } @@ -345,7 +356,7 @@ static void rna_Sequence_frame_offset_end_set(PointerRNA *ptr, int value) Sequence *seq = (Sequence *)ptr->data; Scene *scene = (Scene *)ptr->owner_id; - BKE_sequence_invalidate_cache_composite(scene, seq); + SEQ_relations_invalidate_cache_composite(scene, seq); seq->endofs = value; } @@ -354,7 +365,7 @@ static void rna_Sequence_frame_still_start_set(PointerRNA *ptr, int value) Sequence *seq = (Sequence *)ptr->data; Scene *scene = (Scene *)ptr->owner_id; - BKE_sequence_invalidate_cache_composite(scene, seq); + SEQ_relations_invalidate_cache_composite(scene, seq); seq->startstill = value; } @@ -363,7 +374,7 @@ static void rna_Sequence_frame_still_end_set(PointerRNA *ptr, int value) Sequence *seq = (Sequence *)ptr->data; Scene *scene = (Scene *)ptr->owner_id; - BKE_sequence_invalidate_cache_composite(scene, seq); + SEQ_relations_invalidate_cache_composite(scene, seq); seq->endstill = value; } @@ -374,7 +385,7 @@ static void rna_Sequence_anim_startofs_final_set(PointerRNA *ptr, int value) seq->anim_startofs = MIN2(value, seq->len + seq->anim_startofs); - BKE_sequence_reload_new_file(G.main, scene, seq, false); + SEQ_add_reload_new_file(G.main, scene, seq, false); do_sequence_frame_change_update(scene, seq); } @@ -385,7 +396,7 @@ static void rna_Sequence_anim_endofs_final_set(PointerRNA *ptr, int value) seq->anim_endofs = MIN2(value, seq->len + seq->anim_endofs); - BKE_sequence_reload_new_file(G.main, scene, seq, false); + SEQ_add_reload_new_file(G.main, scene, seq, false); do_sequence_frame_change_update(scene, seq); } @@ -428,43 +439,45 @@ static void rna_Sequence_frame_length_set(PointerRNA *ptr, int value) Sequence *seq = (Sequence *)ptr->data; Scene *scene = (Scene *)ptr->owner_id; - BKE_sequence_invalidate_cache_composite(scene, seq); - BKE_sequence_tx_set_final_right(seq, BKE_sequence_tx_get_final_left(seq, false) + value); + SEQ_relations_invalidate_cache_composite(scene, seq); + SEQ_transform_set_right_handle_frame(seq, + SEQ_transform_get_left_handle_frame(seq, false) + value); do_sequence_frame_change_update(scene, seq); - BKE_sequence_invalidate_cache_composite(scene, seq); + SEQ_relations_invalidate_cache_composite(scene, seq); } static int rna_Sequence_frame_length_get(PointerRNA *ptr) { Sequence *seq = (Sequence *)ptr->data; - return BKE_sequence_tx_get_final_right(seq, false) - BKE_sequence_tx_get_final_left(seq, false); + return SEQ_transform_get_right_handle_frame(seq, false) - + SEQ_transform_get_left_handle_frame(seq, false); } static int rna_Sequence_frame_editable(PointerRNA *ptr, const char **UNUSED(r_info)) { Sequence *seq = (Sequence *)ptr->data; /* Effect sequences' start frame and length must be readonly! */ - return (BKE_sequence_effect_get_num_inputs(seq->type)) ? 0 : PROP_EDITABLE; + return (SEQ_effect_get_num_inputs(seq->type)) ? 0 : PROP_EDITABLE; } static void rna_Sequence_channel_set(PointerRNA *ptr, int value) { Sequence *seq = (Sequence *)ptr->data; Scene *scene = (Scene *)ptr->owner_id; - Editing *ed = BKE_sequencer_editing_get(scene, false); - ListBase *seqbase = BKE_sequence_seqbase(&ed->seqbase, seq); + Editing *ed = SEQ_editing_get(scene, false); + ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seq); - BKE_sequence_invalidate_cache_composite(scene, seq); + SEQ_relations_invalidate_cache_composite(scene, seq); /* check channel increment or decrement */ const int channel_delta = (value >= seq->machine) ? 1 : -1; seq->machine = value; - if (BKE_sequence_test_overlap(seqbase, seq)) { + if (SEQ_transform_test_overlap(seqbase, seq)) { /* XXX - BROKEN!, uses context seqbasep */ - BKE_sequence_base_shuffle_ex(seqbase, seq, scene, channel_delta); + SEQ_transform_seqbase_shuffle_ex(seqbase, seq, scene, channel_delta); } - BKE_sequencer_sort(scene); - BKE_sequence_invalidate_cache_composite(scene, seq); + SEQ_sort(scene); + SEQ_relations_invalidate_cache_composite(scene, seq); } static void rna_Sequence_use_proxy_set(PointerRNA *ptr, bool value) @@ -492,7 +505,7 @@ static Sequence *sequence_get_by_transform(Editing *ed, StripTransform *transfor data.data = transform; /* irritating we need to search for our sequence! */ - BKE_sequencer_base_recursive_apply(&ed->seqbase, transform_seq_cmp_fn, &data); + SEQ_iterator_seqbase_recursive_apply(&ed->seqbase, transform_seq_cmp_fn, &data); return data.seq; } @@ -500,13 +513,13 @@ static Sequence *sequence_get_by_transform(Editing *ed, StripTransform *transfor static char *rna_SequenceTransform_path(PointerRNA *ptr) { Scene *scene = (Scene *)ptr->owner_id; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq = sequence_get_by_transform(ed, ptr->data); if (seq && seq->name + 2) { char name_esc[(sizeof(seq->name) - 2) * 2]; - BLI_strescape(name_esc, seq->name + 2, sizeof(name_esc)); + BLI_str_escape(name_esc, seq->name + 2, sizeof(name_esc)); return BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].transform", name_esc); } else { @@ -519,10 +532,10 @@ static void rna_SequenceTransform_update(Main *UNUSED(bmain), PointerRNA *ptr) { Scene *scene = (Scene *)ptr->owner_id; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq = sequence_get_by_transform(ed, ptr->data); - BKE_sequence_invalidate_cache_preprocessed(scene, seq); + SEQ_relations_invalidate_cache_preprocessed(scene, seq); } static int crop_seq_cmp_fn(Sequence *seq, void *arg_pt) @@ -544,7 +557,7 @@ static Sequence *sequence_get_by_crop(Editing *ed, StripCrop *crop) data.data = crop; /* irritating we need to search for our sequence! */ - BKE_sequencer_base_recursive_apply(&ed->seqbase, crop_seq_cmp_fn, &data); + SEQ_iterator_seqbase_recursive_apply(&ed->seqbase, crop_seq_cmp_fn, &data); return data.seq; } @@ -552,13 +565,13 @@ static Sequence *sequence_get_by_crop(Editing *ed, StripCrop *crop) static char *rna_SequenceCrop_path(PointerRNA *ptr) { Scene *scene = (Scene *)ptr->owner_id; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq = sequence_get_by_crop(ed, ptr->data); if (seq && seq->name + 2) { char name_esc[(sizeof(seq->name) - 2) * 2]; - BLI_strescape(name_esc, seq->name + 2, sizeof(name_esc)); + BLI_str_escape(name_esc, seq->name + 2, sizeof(name_esc)); return BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].crop", name_esc); } else { @@ -569,10 +582,10 @@ static char *rna_SequenceCrop_path(PointerRNA *ptr) static void rna_SequenceCrop_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { Scene *scene = (Scene *)ptr->owner_id; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq = sequence_get_by_crop(ed, ptr->data); - BKE_sequence_invalidate_cache_preprocessed(scene, seq); + SEQ_relations_invalidate_cache_preprocessed(scene, seq); } static void rna_Sequence_text_font_set(PointerRNA *ptr, @@ -583,7 +596,7 @@ static void rna_Sequence_text_font_set(PointerRNA *ptr, TextVars *data = seq->effectdata; VFont *value = ptr_value.data; - BKE_sequencer_text_font_unload(data, true); + SEQ_effect_text_font_unload(data, true); id_us_plus(&value->id); data->text_blf_id = SEQ_FONT_NOT_LOADED; @@ -610,7 +623,7 @@ static void rna_Sequence_name_set(PointerRNA *ptr, const char *value) char oldname[sizeof(seq->name)]; AnimData *adt; - BKE_sequencer_prefetch_stop(scene); + SEQ_prefetch_stop(scene); /* make a copy of the old name first */ BLI_strncpy(oldname, seq->name + 2, sizeof(seq->name) - 2); @@ -619,7 +632,7 @@ static void rna_Sequence_name_set(PointerRNA *ptr, const char *value) BLI_strncpy_utf8(seq->name + 2, value, sizeof(seq->name) - 2); /* make sure the name is unique */ - BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq); + SEQ_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq); /* fix all the animation data which may link to this */ @@ -704,7 +717,7 @@ static char *rna_Sequence_path(PointerRNA *ptr) if (seq->name + 2) { char name_esc[(sizeof(seq->name) - 2) * 2]; - BLI_strescape(name_esc, seq->name + 2, sizeof(name_esc)); + BLI_str_escape(name_esc, seq->name + 2, sizeof(name_esc)); return BLI_sprintfN("sequence_editor.sequences_all[\"%s\"]", name_esc); } else { @@ -730,11 +743,11 @@ static bool rna_MovieSequence_reload_if_needed(ID *scene_id, Sequence *seq, Main bool has_reloaded; bool can_produce_frames; - BKE_sequence_movie_reload_if_needed(bmain, scene, seq, &has_reloaded, &can_produce_frames); + SEQ_add_movie_reload_if_needed(bmain, scene, seq, &has_reloaded, &can_produce_frames); if (has_reloaded && can_produce_frames) { - BKE_sequence_calc(scene, seq); - BKE_sequence_invalidate_cache_raw(scene, seq); + SEQ_time_update_sequence(scene, seq); + SEQ_relations_invalidate_cache_raw(scene, seq); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene); @@ -834,7 +847,7 @@ static int rna_Sequence_input_count_get(PointerRNA *ptr) { Sequence *seq = (Sequence *)(ptr->data); - return BKE_sequence_effect_get_num_inputs(seq->type); + return SEQ_effect_get_num_inputs(seq->type); } static void rna_Sequence_input_set(PointerRNA *ptr, @@ -846,7 +859,7 @@ static void rna_Sequence_input_set(PointerRNA *ptr, Sequence *seq = ptr->data; Sequence *input = ptr_value.data; - if (BKE_sequencer_render_loop_check(input, seq)) { + if (SEQ_relations_render_loop_check(input, seq)) { BKE_report(reports, RPT_ERROR, "Cannot reassign inputs: recursion detected"); return; } @@ -895,13 +908,13 @@ static void rna_SequenceElement_filename_set(PointerRNA *ptr, const char *value) static void rna_Sequence_reopen_files_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) { Scene *scene = (Scene *)ptr->owner_id; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); - BKE_sequencer_free_imbuf(scene, &ed->seqbase, false); + SEQ_relations_free_imbuf(scene, &ed->seqbase, false); rna_Sequence_invalidate_raw_update(bmain, scene, ptr); if (RNA_struct_is_a(ptr->type, &RNA_SoundSequence)) { - BKE_sequencer_update_sound_bounds(scene, ptr->data); + SEQ_sound_update_bounds(scene, ptr->data); } } @@ -909,8 +922,8 @@ static void rna_Sequence_filepath_update(Main *bmain, Scene *UNUSED(scene), Poin { Scene *scene = (Scene *)ptr->owner_id; Sequence *seq = (Sequence *)(ptr->data); - BKE_sequence_reload_new_file(bmain, scene, seq, true); - BKE_sequence_calc(scene, seq); + SEQ_add_reload_new_file(bmain, scene, seq, true); + SEQ_time_update_sequence(scene, seq); rna_Sequence_invalidate_raw_update(bmain, scene, ptr); } @@ -937,26 +950,26 @@ static Sequence *sequence_get_by_proxy(Editing *ed, StripProxy *proxy) data.seq = NULL; data.data = proxy; - BKE_sequencer_base_recursive_apply(&ed->seqbase, seqproxy_seq_cmp_fn, &data); + SEQ_iterator_seqbase_recursive_apply(&ed->seqbase, seqproxy_seq_cmp_fn, &data); return data.seq; } static void rna_Sequence_tcindex_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) { Scene *scene = (Scene *)ptr->owner_id; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq = sequence_get_by_proxy(ed, ptr->data); - BKE_sequence_reload_new_file(bmain, scene, seq, false); + SEQ_add_reload_new_file(bmain, scene, seq, false); do_sequence_frame_change_update(scene, seq); } static void rna_SequenceProxy_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { Scene *scene = (Scene *)ptr->owner_id; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq = sequence_get_by_proxy(ed, ptr->data); - BKE_sequence_invalidate_cache_preprocessed(scene, seq); + SEQ_relations_invalidate_cache_preprocessed(scene, seq); } /* do_versions? */ @@ -1006,7 +1019,7 @@ static Sequence *sequence_get_by_colorbalance(Editing *ed, data.data = cb; /* irritating we need to search for our sequence! */ - BKE_sequencer_base_recursive_apply(&ed->seqbase, colbalance_seq_cmp_fn, &data); + SEQ_iterator_seqbase_recursive_apply(&ed->seqbase, colbalance_seq_cmp_fn, &data); *r_smd = data.smd; @@ -1017,13 +1030,13 @@ static char *rna_SequenceColorBalance_path(PointerRNA *ptr) { Scene *scene = (Scene *)ptr->owner_id; SequenceModifierData *smd; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq = sequence_get_by_colorbalance(ed, ptr->data, &smd); if (seq && seq->name + 2) { char name_esc[(sizeof(seq->name) - 2) * 2]; - BLI_strescape(name_esc, seq->name + 2, sizeof(name_esc)); + BLI_str_escape(name_esc, seq->name + 2, sizeof(name_esc)); if (!smd) { /* path to old filter color balance */ @@ -1033,7 +1046,7 @@ static char *rna_SequenceColorBalance_path(PointerRNA *ptr) /* path to modifier */ char name_esc_smd[sizeof(smd->name) * 2]; - BLI_strescape(name_esc_smd, smd->name, sizeof(name_esc_smd)); + BLI_str_escape(name_esc_smd, smd->name, sizeof(name_esc_smd)); return BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].modifiers[\"%s\"].color_balance", name_esc, name_esc_smd); @@ -1049,17 +1062,17 @@ static void rna_SequenceColorBalance_update(Main *UNUSED(bmain), PointerRNA *ptr) { Scene *scene = (Scene *)ptr->owner_id; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); SequenceModifierData *smd; Sequence *seq = sequence_get_by_colorbalance(ed, ptr->data, &smd); - BKE_sequence_invalidate_cache_preprocessed(scene, seq); + SEQ_relations_invalidate_cache_preprocessed(scene, seq); } static void rna_SequenceEditor_overlay_lock_set(PointerRNA *ptr, bool value) { Scene *scene = (Scene *)ptr->owner_id; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (ed == NULL) { return; @@ -1079,7 +1092,7 @@ static void rna_SequenceEditor_overlay_lock_set(PointerRNA *ptr, bool value) static int rna_SequenceEditor_overlay_frame_get(PointerRNA *ptr) { Scene *scene = (Scene *)ptr->owner_id; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (ed == NULL) { return scene->r.cfra; @@ -1096,7 +1109,7 @@ static int rna_SequenceEditor_overlay_frame_get(PointerRNA *ptr) static void rna_SequenceEditor_overlay_frame_set(PointerRNA *ptr, int value) { Scene *scene = (Scene *)ptr->owner_id; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (ed == NULL) { return; @@ -1130,7 +1143,7 @@ static Sequence *sequence_get_by_modifier(Editing *ed, SequenceModifierData *smd data.data = smd; /* irritating we need to search for our sequence! */ - BKE_sequencer_base_recursive_apply(&ed->seqbase, modifier_seq_cmp_fn, &data); + SEQ_iterator_seqbase_recursive_apply(&ed->seqbase, modifier_seq_cmp_fn, &data); return data.seq; } @@ -1160,7 +1173,7 @@ static StructRNA *rna_SequenceModifier_refine(struct PointerRNA *ptr) static char *rna_SequenceModifier_path(PointerRNA *ptr) { Scene *scene = (Scene *)ptr->owner_id; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); SequenceModifierData *smd = ptr->data; Sequence *seq = sequence_get_by_modifier(ed, smd); @@ -1168,8 +1181,8 @@ static char *rna_SequenceModifier_path(PointerRNA *ptr) char name_esc[(sizeof(seq->name) - 2) * 2]; char name_esc_smd[sizeof(smd->name) * 2]; - BLI_strescape(name_esc, seq->name + 2, sizeof(name_esc)); - BLI_strescape(name_esc_smd, smd->name, sizeof(name_esc_smd)); + BLI_str_escape(name_esc, seq->name + 2, sizeof(name_esc)); + BLI_str_escape(name_esc_smd, smd->name, sizeof(name_esc_smd)); return BLI_sprintfN( "sequence_editor.sequences_all[\"%s\"].modifiers[\"%s\"]", name_esc, name_esc_smd); } @@ -1182,7 +1195,7 @@ static void rna_SequenceModifier_name_set(PointerRNA *ptr, const char *value) { SequenceModifierData *smd = ptr->data; Scene *scene = (Scene *)ptr->owner_id; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq = sequence_get_by_modifier(ed, smd); AnimData *adt; char oldname[sizeof(smd->name)]; @@ -1194,15 +1207,18 @@ static void rna_SequenceModifier_name_set(PointerRNA *ptr, const char *value) BLI_strncpy_utf8(smd->name, value, sizeof(smd->name)); /* make sure the name is truly unique */ - BKE_sequence_modifier_unique_name(seq, smd); + SEQ_modifier_unique_name(seq, smd); /* fix all the animation data which may link to this */ adt = BKE_animdata_from_id(&scene->id); if (adt) { char path[1024]; + char seq_name_esc[(sizeof(seq->name) - 2) * 2]; + BLI_str_escape(seq_name_esc, seq->name + 2, sizeof(seq_name_esc)); + BLI_snprintf( - path, sizeof(path), "sequence_editor.sequences_all[\"%s\"].modifiers", seq->name + 2); + path, sizeof(path), "sequence_editor.sequences_all[\"%s\"].modifiers", seq_name_esc); BKE_animdata_fix_paths_rename(&scene->id, adt, NULL, path, oldname, smd->name, 0, 0, 1); } } @@ -1211,16 +1227,16 @@ static void rna_SequenceModifier_update(Main *UNUSED(bmain), Scene *UNUSED(scene { /* strip from other scenes could be modified, so using active scene is not reliable */ Scene *scene = (Scene *)ptr->owner_id; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq = sequence_get_by_modifier(ed, ptr->data); - BKE_sequence_invalidate_cache_preprocessed(scene, seq); + SEQ_relations_invalidate_cache_preprocessed(scene, seq); } static bool rna_SequenceModifier_otherSequence_poll(PointerRNA *ptr, PointerRNA value) { Scene *scene = (Scene *)ptr->owner_id; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq = sequence_get_by_modifier(ed, ptr->data); Sequence *cur = (Sequence *)value.data; @@ -1234,7 +1250,7 @@ static bool rna_SequenceModifier_otherSequence_poll(PointerRNA *ptr, PointerRNA static SequenceModifierData *rna_Sequence_modifier_new( Sequence *seq, bContext *C, ReportList *reports, const char *name, int type) { - if (!BKE_sequence_supports_modifiers(seq)) { + if (!SEQ_sequence_supports_modifiers(seq)) { BKE_report(reports, RPT_ERROR, "Sequence type does not support modifiers"); return NULL; @@ -1243,9 +1259,9 @@ static SequenceModifierData *rna_Sequence_modifier_new( Scene *scene = CTX_data_scene(C); SequenceModifierData *smd; - smd = BKE_sequence_modifier_new(seq, name, type); + smd = SEQ_modifier_new(seq, name, type); - BKE_sequence_invalidate_cache_preprocessed(scene, seq); + SEQ_relations_invalidate_cache_preprocessed(scene, seq); WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, NULL); @@ -1261,13 +1277,13 @@ static void rna_Sequence_modifier_remove(Sequence *seq, SequenceModifierData *smd = smd_ptr->data; Scene *scene = CTX_data_scene(C); - if (BKE_sequence_modifier_remove(seq, smd) == false) { + if (SEQ_modifier_remove(seq, smd) == false) { BKE_report(reports, RPT_ERROR, "Modifier was not found in the stack"); return; } RNA_POINTER_INVALIDATE(smd_ptr); - BKE_sequence_invalidate_cache_preprocessed(scene, seq); + SEQ_relations_invalidate_cache_preprocessed(scene, seq); WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, NULL); } @@ -1276,9 +1292,9 @@ static void rna_Sequence_modifier_clear(Sequence *seq, bContext *C) { Scene *scene = CTX_data_scene(C); - BKE_sequence_modifier_clear(seq); + SEQ_modifier_clear(seq); - BKE_sequence_invalidate_cache_preprocessed(scene, seq); + SEQ_relations_invalidate_cache_preprocessed(scene, seq); WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, NULL); } @@ -1289,11 +1305,11 @@ static void rna_SequenceModifier_strip_set(PointerRNA *ptr, { SequenceModifierData *smd = ptr->data; Scene *scene = (Scene *)ptr->owner_id; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq = sequence_get_by_modifier(ed, smd); Sequence *target = (Sequence *)value.data; - if (target != NULL && BKE_sequencer_render_loop_check(target, seq)) { + if (target != NULL && SEQ_relations_render_loop_check(target, seq)) { BKE_report(reports, RPT_ERROR, "Recursion detected, can not use this strip"); return; } @@ -1305,7 +1321,7 @@ static float rna_Sequence_fps_get(PointerRNA *ptr) { Scene *scene = (Scene *)ptr->owner_id; Sequence *seq = (Sequence *)(ptr->data); - return BKE_sequence_get_fps(scene, seq); + return SEQ_time_sequence_get_fps(scene, seq); } #else @@ -2085,13 +2101,6 @@ static void rna_def_editor(BlenderRNA *brna) "Prefetch Frames", "Render frames ahead of current frame in the background for faster playback"); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, NULL); - - prop = RNA_def_property(srna, "recycle_max_cost", PROP_FLOAT, PROP_NONE); - RNA_def_property_range(prop, 0.0f, SEQ_CACHE_COST_MAX); - RNA_def_property_ui_range(prop, 0.0f, SEQ_CACHE_COST_MAX, 0.1f, 1); - RNA_def_property_float_sdna(prop, NULL, "recycle_max_cost"); - RNA_def_property_ui_text( - prop, "Recycle Up to Cost", "Only frames with cost lower than this value will be recycled"); } static void rna_def_filter_video(StructRNA *srna) diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c index 6f97098900e..070fb08c3b4 100644 --- a/source/blender/makesrna/intern/rna_sequencer_api.c +++ b/source/blender/makesrna/intern/rna_sequencer_api.c @@ -51,6 +51,10 @@ # include "IMB_imbuf.h" # include "IMB_imbuf_types.h" +# include "SEQ_add.h" +# include "SEQ_edit.h" +# include "SEQ_relations.h" +# include "SEQ_render.h" # include "SEQ_sequencer.h" # include "WM_api.h" @@ -58,11 +62,11 @@ static void rna_Sequence_update_rnafunc(ID *id, Sequence *self, bool do_data) { if (do_data) { - BKE_sequencer_update_changed_seq_and_deps((Scene *)id, self, true, true); + SEQ_relations_update_changed_seq_and_deps((Scene *)id, self, true, true); // new_tstripdata(self); /* need 2.6x version of this. */ } - BKE_sequence_calc((Scene *)id, self); - BKE_sequence_calc_disp((Scene *)id, self); + SEQ_time_update_sequence((Scene *)id, self); + SEQ_time_update_sequence_bounds((Scene *)id, self); } static void rna_Sequence_swap_internal(Sequence *seq_self, @@ -71,7 +75,7 @@ static void rna_Sequence_swap_internal(Sequence *seq_self, { const char *error_msg; - if (BKE_sequence_swap(seq_self, seq_other, &error_msg) == 0) { + if (SEQ_edit_sequence_swap(seq_self, seq_other, &error_msg) == 0) { BKE_report(reports, RPT_ERROR, error_msg); } } @@ -82,10 +86,10 @@ static Sequence *alloc_generic_sequence( Sequence *seq; StripElem *se; - seq = BKE_sequence_alloc(seqbase, frame_start, channel, type); + seq = SEQ_sequence_alloc(seqbase, frame_start, channel, type); BLI_strncpy(seq->name + 2, name, sizeof(seq->name) - 2); - BKE_sequence_base_unique_name_recursive(seqbase, seq); + SEQ_sequence_base_unique_name_recursive(seqbase, seq); Strip *strip = seq->strip; @@ -121,7 +125,7 @@ static Sequence *rna_Sequences_new_clip(ID *id, seq->len = BKE_movieclip_get_duration(clip); id_us_plus((ID *)clip); - BKE_sequence_calc_disp(scene, seq); + SEQ_time_update_sequence_bounds(scene, seq); DEG_relations_tag_update(bmain); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); @@ -168,8 +172,8 @@ static Sequence *rna_Sequences_new_mask(ID *id, seq->len = BKE_mask_get_duration(mask); id_us_plus((ID *)mask); - BKE_sequence_calc_disp(scene, seq); - BKE_sequence_invalidate_cache_composite(scene, seq); + SEQ_time_update_sequence_bounds(scene, seq); + SEQ_relations_invalidate_cache_composite(scene, seq); DEG_relations_tag_update(bmain); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); @@ -205,8 +209,8 @@ static Sequence *rna_Sequences_new_scene(ID *id, seq->len = sce_seq->r.efra - sce_seq->r.sfra + 1; id_us_plus((ID *)sce_seq); - BKE_sequence_calc_disp(scene, seq); - BKE_sequence_invalidate_cache_composite(scene, seq); + SEQ_time_update_sequence_bounds(scene, seq); + SEQ_relations_invalidate_cache_composite(scene, seq); DEG_relations_tag_update(bmain); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); @@ -255,12 +259,12 @@ static Sequence *rna_Sequences_new_image(ID *id, if (seq->strip->stripdata->name[0] == '\0') { BKE_report(reports, RPT_ERROR, "Sequences.new_image: unable to open image file"); BLI_remlink(seqbase, seq); - BKE_sequence_free(scene, seq, true); + SEQ_sequence_free(scene, seq, true); return NULL; } - BKE_sequence_calc_disp(scene, seq); - BKE_sequence_invalidate_cache_composite(scene, seq); + SEQ_time_update_sequence_bounds(scene, seq); + SEQ_relations_invalidate_cache_composite(scene, seq); DEG_relations_tag_update(bmain); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); @@ -318,8 +322,8 @@ static Sequence *rna_Sequences_new_movie( seq->len = IMB_anim_get_duration(an, IMB_TC_RECORD_RUN); } - BKE_sequence_calc_disp(scene, seq); - BKE_sequence_invalidate_cache_composite(scene, seq); + SEQ_time_update_sequence_bounds(scene, seq); + SEQ_relations_invalidate_cache_composite(scene, seq); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene); @@ -365,7 +369,7 @@ static Sequence *rna_Sequences_new_sound(ID *id, seq->sound = sound; seq->len = ceil((double)info.length * FPS); - BKE_sequence_calc_disp(scene, seq); + SEQ_time_update_sequence_bounds(scene, seq); DEG_relations_tag_update(bmain); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); @@ -429,7 +433,7 @@ static Sequence *rna_Sequences_new_effect(ID *id, Scene *scene = (Scene *)id; Sequence *seq; struct SeqEffectHandle sh; - int num_inputs = BKE_sequence_effect_get_num_inputs(type); + int num_inputs = SEQ_effect_get_num_inputs(type); switch (num_inputs) { case 0: @@ -467,7 +471,7 @@ static Sequence *rna_Sequences_new_effect(ID *id, seq = alloc_generic_sequence(seqbase, name, frame_start, channel, type, NULL); - sh = BKE_sequence_get_effect(seq); + sh = SEQ_effect_handle_get(seq); seq->seq1 = seq1; seq->seq2 = seq2; @@ -477,14 +481,14 @@ static Sequence *rna_Sequences_new_effect(ID *id, if (!seq1) { /* effect has no deps */ seq->len = 1; - BKE_sequence_tx_set_final_right(seq, frame_end); + SEQ_transform_set_right_handle_frame(seq, frame_end); } seq->flag |= SEQ_USE_EFFECT_DEFAULT_FADE; - BKE_sequence_calc(scene, seq); - BKE_sequence_calc_disp(scene, seq); - BKE_sequence_invalidate_cache_composite(scene, seq); + SEQ_time_update_sequence(scene, seq); + SEQ_time_update_sequence_bounds(scene, seq); + SEQ_relations_invalidate_cache_composite(scene, seq); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene); @@ -536,8 +540,8 @@ static void rna_Sequences_remove( return; } - BKE_sequencer_flag_for_removal(scene, seqbase, seq); - BKE_sequencer_remove_flagged_sequences(scene, seqbase); + SEQ_edit_flag_for_removal(scene, seqbase, seq); + SEQ_edit_remove_flagged_sequences(scene, seqbase); RNA_POINTER_INVALIDATE(seq_ptr); DEG_relations_tag_update(bmain); @@ -568,7 +572,7 @@ static StripElem *rna_SequenceElements_append(ID *id, Sequence *seq, const char BLI_strncpy(se->name, filename, sizeof(se->name)); seq->len++; - BKE_sequence_calc_disp(scene, seq); + SEQ_time_update_sequence_bounds(scene, seq); WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene); return se; @@ -609,7 +613,7 @@ static void rna_SequenceElements_pop(ID *id, Sequence *seq, ReportList *reports, MEM_freeN(seq->strip->stripdata); seq->strip->stripdata = new_seq; - BKE_sequence_calc_disp(scene, seq); + SEQ_time_update_sequence_bounds(scene, seq); WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene); } @@ -618,13 +622,13 @@ static void rna_Sequence_invalidate_cache_rnafunc(ID *id, Sequence *self, int ty { switch (type) { case SEQ_CACHE_STORE_RAW: - BKE_sequence_invalidate_cache_raw((Scene *)id, self); + SEQ_relations_invalidate_cache_raw((Scene *)id, self); break; case SEQ_CACHE_STORE_PREPROCESSED: - BKE_sequence_invalidate_cache_preprocessed((Scene *)id, self); + SEQ_relations_invalidate_cache_preprocessed((Scene *)id, self); break; case SEQ_CACHE_STORE_COMPOSITE: - BKE_sequence_invalidate_cache_composite((Scene *)id, self); + SEQ_relations_invalidate_cache_composite((Scene *)id, self); break; } } diff --git a/source/blender/makesrna/intern/rna_shader_fx.c b/source/blender/makesrna/intern/rna_shader_fx.c index 7b039b91188..451cc56eba7 100644 --- a/source/blender/makesrna/intern/rna_shader_fx.c +++ b/source/blender/makesrna/intern/rna_shader_fx.c @@ -161,7 +161,7 @@ static char *rna_ShaderFx_path(PointerRNA *ptr) ShaderFxData *gmd = ptr->data; char name_esc[sizeof(gmd->name) * 2]; - BLI_strescape(name_esc, gmd->name, sizeof(name_esc)); + BLI_str_escape(name_esc, gmd->name, sizeof(name_esc)); return BLI_sprintfN("shader_effects[\"%s\"]", name_esc); } diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index eabb71c79d3..acfb317c616 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -53,7 +53,7 @@ #include "rna_internal.h" -#include "SEQ_sequencer.h" +#include "SEQ_relations.h" #include "WM_api.h" #include "WM_types.h" @@ -170,6 +170,12 @@ const EnumPropertyItem rna_enum_space_sequencer_view_type_items[] = { {0, NULL, 0, NULL, NULL}, }; +const EnumPropertyItem rna_enum_space_file_browse_mode_items[] = { + {FILE_BROWSE_MODE_FILES, "FILES", ICON_FILEBROWSER, "File Browser", ""}, + {FILE_BROWSE_MODE_ASSETS, "ASSETS", ICON_ASSET_MANAGER, "Asset Browser", ""}, + {0, NULL, 0, NULL, NULL}, +}; + #define SACT_ITEM_DOPESHEET \ { \ SACTCONT_DOPESHEET, "DOPESHEET", ICON_ACTION, "Dope Sheet", "Edit all keyframes in scene" \ @@ -412,12 +418,7 @@ static const EnumPropertyItem rna_enum_view3dshading_render_pass_type_items[] = {EEVEE_RENDER_PASS_DIFFUSE_COLOR, "DIFFUSE_COLOR", 0, "Diffuse Color", ""}, {EEVEE_RENDER_PASS_SPECULAR_LIGHT, "SPECULAR_LIGHT", 0, "Specular Light", ""}, {EEVEE_RENDER_PASS_SPECULAR_COLOR, "SPECULAR_COLOR", 0, "Specular Color", ""}, - {EEVEE_RENDER_PASS_VOLUME_TRANSMITTANCE, - "VOLUME_TRANSMITTANCE", - 0, - "Volume Transmittance", - ""}, - {EEVEE_RENDER_PASS_VOLUME_SCATTER, "VOLUME_SCATTER", 0, "Volume Scattering", ""}, + {EEVEE_RENDER_PASS_VOLUME_LIGHT, "VOLUME_LIGHT", 0, "Volume Light", ""}, {0, "", ICON_NONE, "Effects", ""}, {EEVEE_RENDER_PASS_BLOOM, "BLOOM", 0, "Bloom", ""}, @@ -509,6 +510,7 @@ static const EnumPropertyItem rna_enum_curve_display_handle_items[] = { # include "BKE_layer.h" # include "BKE_nla.h" # include "BKE_paint.h" +# include "BKE_preferences.h" # include "BKE_scene.h" # include "BKE_screen.h" # include "BKE_workspace.h" @@ -2113,7 +2115,7 @@ static void rna_SpaceDopeSheetEditor_action_update(bContext *C, PointerRNA *ptr) * and the user then uses the browse menu to get back to this action, * assigning it as the active action (i.e. the stash strip gets out of sync) */ - BKE_nla_action_stash(adt); + BKE_nla_action_stash(adt, ID_IS_OVERRIDE_LIBRARY(id)); } BKE_animdata_set_action(NULL, id, saction->action); @@ -2221,7 +2223,7 @@ static void rna_SequenceEditor_update_cache(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr)) { - BKE_sequencer_cache_cleanup(scene); + SEQ_cache_cleanup(scene); } static void rna_Sequencer_view_type_update(Main *UNUSED(bmain), @@ -2467,6 +2469,177 @@ static PointerRNA rna_FileSelectParams_filter_id_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_FileSelectIDFilter, ptr->data); } +static int rna_FileAssetSelectParams_asset_library_get(PointerRNA *ptr) +{ + FileAssetSelectParams *params = ptr->data; + /* Just an extra sanity check to ensure this isn't somehow called for RNA_FileSelectParams. */ + BLI_assert(ptr->type == &RNA_FileAssetSelectParams); + + /* Simple case: Predefined repo, just set the value. */ + if (params->asset_library.type < FILE_ASSET_LIBRARY_CUSTOM) { + return params->asset_library.type; + } + + /* Note that the path isn't checked for validity here. If an invalid library path is used, the + * Asset Browser can give a nice hint on what's wrong. */ + const bUserAssetLibrary *user_library = BKE_preferences_asset_library_find_from_index( + &U, params->asset_library.custom_library_index); + if (user_library) { + return FILE_ASSET_LIBRARY_CUSTOM + params->asset_library.custom_library_index; + } + + BLI_assert(0); + return FILE_ASSET_LIBRARY_LOCAL; +} + +static void rna_FileAssetSelectParams_asset_library_set(PointerRNA *ptr, int value) +{ + FileAssetSelectParams *params = ptr->data; + + /* Simple case: Predefined repo, just set the value. */ + if (value < FILE_ASSET_LIBRARY_CUSTOM) { + params->asset_library.type = value; + params->asset_library.custom_library_index = -1; + BLI_assert(ELEM(value, FILE_ASSET_LIBRARY_LOCAL)); + return; + } + + const bUserAssetLibrary *user_library = BKE_preferences_asset_library_find_from_index( + &U, value - FILE_ASSET_LIBRARY_CUSTOM); + + /* Note that the path isn't checked for validity here. If an invalid library path is used, the + * Asset Browser can give a nice hint on what's wrong. */ + const bool is_valid = (user_library->name[0] && user_library->path[0]); + if (!user_library) { + params->asset_library.type = FILE_ASSET_LIBRARY_LOCAL; + params->asset_library.custom_library_index = -1; + } + else if (user_library && is_valid) { + params->asset_library.custom_library_index = value - FILE_ASSET_LIBRARY_CUSTOM; + params->asset_library.type = FILE_ASSET_LIBRARY_CUSTOM; + } +} + +static const EnumPropertyItem *rna_FileAssetSelectParams_asset_library_itemf( + bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) +{ + const EnumPropertyItem predefined_items[] = { + /* For the future. */ + // {FILE_ASSET_REPO_BUNDLED, "BUNDLED", 0, "Bundled", "Show the default user assets"}, + {FILE_ASSET_LIBRARY_LOCAL, + "LOCAL", + ICON_BLENDER, + "Current File", + "Show the assets currently available in this Blender session"}, + {0, NULL, 0, NULL, NULL}, + }; + + EnumPropertyItem *item = NULL; + int totitem = 0; + + /* Add separator if needed. */ + if (!BLI_listbase_is_empty(&U.asset_libraries)) { + const EnumPropertyItem sepr = {0, "", 0, "Custom", NULL}; + RNA_enum_item_add(&item, &totitem, &sepr); + } + + int i = 0; + for (bUserAssetLibrary *user_library = U.asset_libraries.first; user_library; + user_library = user_library->next, i++) { + /* Note that the path itself isn't checked for validity here. If an invalid library path is + * used, the Asset Browser can give a nice hint on what's wrong. */ + const bool is_valid = (user_library->name[0] && user_library->path[0]); + if (!is_valid) { + continue; + } + + /* Use library path as description, it's a nice hint for users. */ + EnumPropertyItem tmp = {FILE_ASSET_LIBRARY_CUSTOM + i, + user_library->name, + ICON_NONE, + user_library->name, + user_library->path}; + RNA_enum_item_add(&item, &totitem, &tmp); + } + + if (totitem) { + const EnumPropertyItem sepr = {0, "", 0, "Built-in", NULL}; + RNA_enum_item_add(&item, &totitem, &sepr); + } + + /* Add predefined items. */ + RNA_enum_items_add(&item, &totitem, predefined_items); + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + return item; +} + +static void rna_FileAssetSelectParams_asset_category_set(PointerRNA *ptr, uint64_t value) +{ + FileSelectParams *params = ptr->data; + params->filter_id = value; +} + +static uint64_t rna_FileAssetSelectParams_asset_category_get(PointerRNA *ptr) +{ + FileSelectParams *params = ptr->data; + return params->filter_id; +} + +static void rna_FileBrowser_FileSelectEntry_name_get(PointerRNA *ptr, char *value) +{ + const FileDirEntry *entry = ptr->data; + strcpy(value, entry->name); +} + +static int rna_FileBrowser_FileSelectEntry_name_length(PointerRNA *ptr) +{ + const FileDirEntry *entry = ptr->data; + return (int)strlen(entry->name); +} + +static int rna_FileBrowser_FileSelectEntry_preview_icon_id_get(PointerRNA *ptr) +{ + const FileDirEntry *entry = ptr->data; + return ED_file_icon(entry); +} + +static PointerRNA rna_FileBrowser_FileSelectEntry_asset_data_get(PointerRNA *ptr) +{ + const FileDirEntry *entry = ptr->data; + return rna_pointer_inherit_refine(ptr, &RNA_AssetMetaData, entry->asset_data); +} + +static StructRNA *rna_FileBrowser_params_typef(PointerRNA *ptr) +{ + SpaceFile *sfile = ptr->data; + FileSelectParams *params = ED_fileselect_get_active_params(sfile); + + if (params == ED_fileselect_get_file_params(sfile)) { + return &RNA_FileSelectParams; + } + if (params == (void *)ED_fileselect_get_asset_params(sfile)) { + return &RNA_FileAssetSelectParams; + } + + BLI_assert(!"Could not identify file select parameters"); + return NULL; +} + +static PointerRNA rna_FileBrowser_params_get(PointerRNA *ptr) +{ + SpaceFile *sfile = ptr->data; + FileSelectParams *params = ED_fileselect_get_active_params(sfile); + StructRNA *params_struct = rna_FileBrowser_params_typef(ptr); + + if (params && params_struct) { + return rna_pointer_inherit_refine(ptr, params_struct, params); + } + + return rna_pointer_inherit_refine(ptr, NULL, NULL); +} + static void rna_FileBrowser_FSMenuEntry_path_get(PointerRNA *ptr, char *value) { char *path = ED_fsmenu_entry_get_path(ptr->data); @@ -2777,6 +2950,14 @@ static void rna_FileBrowser_FSMenuRecent_active_range( rna_FileBrowser_FSMenu_active_range(ptr, min, max, softmin, softmax, FS_CATEGORY_RECENT); } +static void rna_SpaceFileBrowser_browse_mode_update(Main *UNUSED(bmain), + Scene *UNUSED(scene), + PointerRNA *ptr) +{ + ScrArea *area = rna_area_from_space(ptr); + ED_area_tag_refresh(area); +} + #else static const EnumPropertyItem dt_uv_items[] = { @@ -4269,7 +4450,8 @@ static void rna_def_space_view3d(BlenderRNA *brna) /* Camera Object Data. */ prop = RNA_def_property(srna, "show_gizmo_camera_lens", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "gizmo_show_camera", V3D_GIZMO_SHOW_CAMERA_LENS); - RNA_def_property_ui_text(prop, "Show Camera Lens", "Gizmo to adjust camera lens & ortho size"); + RNA_def_property_ui_text( + prop, "Show Camera Lens", "Gizmo to adjust camera focal length or orthographic scale"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); prop = RNA_def_property(srna, "show_gizmo_camera_dof_distance", PROP_BOOLEAN, PROP_NONE); @@ -4994,7 +5176,7 @@ static void rna_def_space_sequencer(BlenderRNA *brna) prop = RNA_def_property(srna, "waveform_display_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); RNA_def_property_enum_items(prop, waveform_type_display_items); - RNA_def_property_ui_text(prop, "Waveform Displaying", "How Waveforms are drawn"); + RNA_def_property_ui_text(prop, "Waveform Display", "How Waveforms are drawn"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL); prop = RNA_def_property(srna, "use_zoom_to_fit", PROP_BOOLEAN, PROP_NONE); @@ -5047,6 +5229,27 @@ static void rna_def_space_sequencer(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_SHOW_FCURVES); RNA_def_property_ui_text(prop, "Show F-Curves", "Display strip opacity/volume curve"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL); + + prop = RNA_def_property(srna, "show_strip_overlay", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_SHOW_STRIP_OVERLAY); + RNA_def_property_ui_text(prop, "Show Overlay", ""); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL); + + prop = RNA_def_property(srna, "show_strip_name", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_SHOW_STRIP_NAME); + RNA_def_property_ui_text(prop, "Show Name", ""); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL); + + prop = RNA_def_property(srna, "show_strip_source", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_SHOW_STRIP_SOURCE); + RNA_def_property_ui_text( + prop, "Show Source", "Display path to source file, or name of source datablock"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL); + + prop = RNA_def_property(srna, "show_strip_duration", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_SHOW_STRIP_DURATION); + RNA_def_property_ui_text(prop, "Show Duration", ""); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL); } static void rna_def_space_text(BlenderRNA *brna) @@ -5479,7 +5682,7 @@ static void rna_def_space_graph(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", SIPO_NORMALIZE); RNA_def_property_ui_text(prop, "Use Normalization", - "Display curves in normalized to -1..1 range, " + "Display curves in normalized range from -1 to 1, " "for easier editing of multiple curves with different ranges"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL); @@ -5786,6 +5989,44 @@ static void rna_def_fileselect_idfilter(BlenderRNA *brna) } } +static void rna_def_fileselect_entry(BlenderRNA *brna) +{ + PropertyRNA *prop; + StructRNA *srna = RNA_def_struct(brna, "FileSelectEntry", NULL); + RNA_def_struct_sdna(srna, "FileDirEntry"); + RNA_def_struct_ui_text(srna, "File Select Entry", "A file viewable in the File Browser"); + + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_string_funcs(prop, + "rna_FileBrowser_FileSelectEntry_name_get", + "rna_FileBrowser_FileSelectEntry_name_length", + NULL); + RNA_def_property_ui_text(prop, "Name", ""); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_struct_name_property(srna, prop); + + prop = RNA_def_int( + srna, + "preview_icon_id", + 0, + INT_MIN, + INT_MAX, + "Icon ID", + "Unique integer identifying the preview of this file as an icon (zero means invalid)", + INT_MIN, + INT_MAX); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_int_funcs( + prop, "rna_FileBrowser_FileSelectEntry_preview_icon_id_get", NULL, NULL); + + prop = RNA_def_property(srna, "asset_data", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "AssetMetaData"); + RNA_def_property_pointer_funcs( + prop, "rna_FileBrowser_FileSelectEntry_asset_data_get", NULL, NULL, NULL); + RNA_def_property_ui_text( + prop, "Asset Data", "Asset data, valid if the file represents an asset"); +} + static void rna_def_fileselect_params(BlenderRNA *brna) { StructRNA *srna; @@ -5958,6 +6199,12 @@ static void rna_def_fileselect_params(BlenderRNA *brna) RNA_def_property_ui_icon(prop, ICON_BLENDER, 0); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); + prop = RNA_def_property(srna, "use_filter_asset_only", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", FILE_ASSETS_ONLY); + RNA_def_property_ui_text( + prop, "Only Assets", "Hide .blend files items that are not data-blocks with asset metadata"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); + prop = RNA_def_property(srna, "filter_id", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_struct_type(prop, "FileSelectIDFilter"); @@ -5989,6 +6236,75 @@ static void rna_def_fileselect_params(BlenderRNA *brna) RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_LIST, NULL); } +static void rna_def_fileselect_asset_params(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + /* XXX copied from rna_def_fileselect_idfilter. */ + static const EnumPropertyItem asset_category_items[] = { + {FILTER_ID_SCE, "SCENES", ICON_SCENE_DATA, "Scenes", "Show scenes"}, + {FILTER_ID_AC, "ANIMATIONS", ICON_ANIM_DATA, "Animations", "Show animation data"}, + {FILTER_ID_OB | FILTER_ID_GR, + "OBJECTS_AND_COLLECTIONS", + ICON_GROUP, + "Objects & Collections", + "Show objects and collections"}, + {FILTER_ID_AR | FILTER_ID_CU | FILTER_ID_LT | FILTER_ID_MB | FILTER_ID_ME + /* XXX avoid warning */ + // | FILTER_ID_HA | FILTER_ID_PT | FILTER_ID_VO + , + "GEOMETRY", + ICON_MESH_DATA, + "Geometry", + "Show meshes, curves, lattice, armatures and metaballs data"}, + {FILTER_ID_LS | FILTER_ID_MA | FILTER_ID_NT | FILTER_ID_TE, + "SHADING", + ICON_MATERIAL_DATA, + "Shading", + "Show materials, nodetrees, textures and Freestyle's linestyles"}, + {FILTER_ID_IM | FILTER_ID_MC | FILTER_ID_MSK | FILTER_ID_SO, + "IMAGES_AND_SOUNDS", + ICON_IMAGE_DATA, + "Images & Sounds", + "Show images, movie clips, sounds and masks"}, + {FILTER_ID_CA | FILTER_ID_LA | FILTER_ID_LP | FILTER_ID_SPK | FILTER_ID_WO | FILTER_ID_WS, + "ENVIRONMENTS", + ICON_WORLD_DATA, + "Environment", + "Show worlds, lights, cameras and speakers"}, + {FILTER_ID_BR | FILTER_ID_GD | FILTER_ID_PA | FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_TXT | + FILTER_ID_VF | FILTER_ID_CF, + "MISC", + ICON_GREASEPENCIL, + "Miscellaneous", + "Show other data types"}, + {0, NULL, 0, NULL, NULL}, + }; + + srna = RNA_def_struct(brna, "FileAssetSelectParams", "FileSelectParams"); + RNA_def_struct_ui_text( + srna, "Asset Select Parameters", "Settings for the file selection in Asset Browser mode"); + + prop = RNA_def_property(srna, "asset_library", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, DummyRNA_NULL_items); + RNA_def_property_enum_funcs(prop, + "rna_FileAssetSelectParams_asset_library_get", + "rna_FileAssetSelectParams_asset_library_set", + "rna_FileAssetSelectParams_asset_library_itemf"); + RNA_def_property_ui_text(prop, "Asset Library", ""); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); + + prop = RNA_def_property(srna, "asset_category", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, asset_category_items); + RNA_def_property_enum_funcs(prop, + "rna_FileAssetSelectParams_asset_category_get", + "rna_FileAssetSelectParams_asset_category_set", + NULL); + RNA_def_property_ui_text(prop, "Asset Category", "Determine which kind of assets to display"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_LIST, NULL); +} + static void rna_def_filemenu_entry(BlenderRNA *brna) { StructRNA *srna; @@ -6042,8 +6358,18 @@ static void rna_def_space_filebrowser(BlenderRNA *brna) rna_def_space_generic_show_region_toggles(srna, (1 << RGN_TYPE_TOOLS) | (1 << RGN_TYPE_UI)); + prop = RNA_def_property(srna, "browse_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_enum_space_file_browse_mode_items); + RNA_def_property_ui_text( + prop, + "Browsing Mode", + "Type of the File Editor view (regular file browsing or asset browsing)"); + RNA_def_property_update(prop, 0, "rna_SpaceFileBrowser_browse_mode_update"); + prop = RNA_def_property(srna, "params", PROP_POINTER, PROP_NONE); - RNA_def_property_pointer_sdna(prop, NULL, "params"); + RNA_def_property_struct_type(prop, "FileSelectParams"); + RNA_def_property_pointer_funcs( + prop, "rna_FileBrowser_params_get", NULL, "rna_FileBrowser_params_typef", NULL); RNA_def_property_ui_text( prop, "Filebrowser Parameter", "Parameters and Settings for the Filebrowser"); @@ -6791,7 +7117,9 @@ void RNA_def_space(BlenderRNA *brna) rna_def_space_image(brna); rna_def_space_sequencer(brna); rna_def_space_text(brna); + rna_def_fileselect_entry(brna); rna_def_fileselect_params(brna); + rna_def_fileselect_asset_params(brna); rna_def_fileselect_idfilter(brna); rna_def_filemenu_entry(brna); rna_def_space_filebrowser(brna); diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c index fb6d40b3a55..cf8abf26c0a 100644 --- a/source/blender/makesrna/intern/rna_texture.c +++ b/source/blender/makesrna/intern/rna_texture.c @@ -148,6 +148,7 @@ static const EnumPropertyItem blend_type_items[] = { # include "BKE_texture.h" # include "DEG_depsgraph.h" +# include "DEG_depsgraph_build.h" # include "ED_node.h" # include "ED_render.h" @@ -233,6 +234,12 @@ static void rna_Texture_type_set(PointerRNA *ptr, int value) BKE_texture_type_set(tex, value); } +void rna_TextureSlotTexture_update(bContext *C, PointerRNA *ptr) +{ + DEG_relations_tag_update(CTX_data_main(C)); + rna_TextureSlot_update(C, ptr); +} + void rna_TextureSlot_update(bContext *C, PointerRNA *ptr) { ID *id = ptr->owner_id; @@ -317,7 +324,7 @@ char *rna_TextureSlot_path(PointerRNA *ptr) if (mtex->tex) { char name_esc[(sizeof(mtex->tex->id.name) - 2) * 2]; - BLI_strescape(name_esc, mtex->tex->id.name + 2, sizeof(name_esc)); + BLI_str_escape(name_esc, mtex->tex->id.name + 2, sizeof(name_esc)); return BLI_sprintfN("texture_slots[\"%s\"]", name_esc); } else { @@ -623,7 +630,7 @@ static void rna_def_mtex(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_EDITABLE | PROP_CONTEXT_UPDATE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Texture", "Texture data-block used by this texture slot"); - RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING_LINKS, "rna_TextureSlot_update"); + RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING_LINKS, "rna_TextureSlotTexture_update"); prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); RNA_def_property_string_funcs( diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c index 51cc178ab15..b86f5b789da 100644 --- a/source/blender/makesrna/intern/rna_ui.c +++ b/source/blender/makesrna/intern/rna_ui.c @@ -1200,6 +1200,11 @@ static void rna_def_ui_layout(BlenderRNA *brna) {UI_EMBOSS_NONE, "NONE", 0, "None", "Draw only text and icons"}, {UI_EMBOSS_PULLDOWN, "PULLDOWN_MENU", 0, "Pulldown Menu", "Draw pulldown menu style"}, {UI_EMBOSS_RADIAL, "RADIAL_MENU", 0, "Radial Menu", "Draw radial menu style"}, + {UI_EMBOSS_NONE_OR_STATUS, + "UI_EMBOSS_NONE_OR_STATUS", + 0, + "None or Status", + "Draw with no emboss unless the button has a coloring status like an animation state"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c index 447f5b4210b..e26cc8d8d41 100644 --- a/source/blender/makesrna/intern/rna_ui_api.c +++ b/source/blender/makesrna/intern/rna_ui_api.c @@ -480,6 +480,7 @@ static void rna_uiTemplateID(uiLayout *layout, PointerRNA *ptr, const char *propname, const char *newop, + const char *duplicateop, const char *openop, const char *unlinkop, int filter, @@ -498,7 +499,8 @@ static void rna_uiTemplateID(uiLayout *layout, /* Get translated name (label). */ name = rna_translate_ui_text(name, text_ctxt, NULL, prop, translate); - uiTemplateID(layout, C, ptr, propname, newop, openop, unlinkop, filter, live_icon, name); + uiTemplateID( + layout, C, ptr, propname, newop, duplicateop, openop, unlinkop, filter, live_icon, name); } static void rna_uiTemplateAnyID(uiLayout *layout, @@ -1156,8 +1158,11 @@ void RNA_api_ui_layout(StructRNA *srna) api_ui_item_rna_common(func); RNA_def_string(func, "new", NULL, 0, "", "Operator identifier to create a new ID block"); RNA_def_string( + func, "duplicate", NULL, 0, "", "Operator identifier to duplicate the selected ID block"); + RNA_def_string( func, "open", NULL, 0, "", "Operator identifier to open a file for creating a new ID block"); - RNA_def_string(func, "unlink", NULL, 0, "", "Operator identifier to unlink the ID block"); + RNA_def_string( + func, "unlink", NULL, 0, "", "Operator identifier to unlink the selected ID block"); RNA_def_enum(func, "filter", id_template_filter_items, diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 628eff54032..ebcff76aa36 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -184,6 +184,7 @@ static const EnumPropertyItem rna_enum_userdef_viewport_aa_items[] = { # include "BKE_mesh_runtime.h" # include "BKE_paint.h" # include "BKE_pbvh.h" +# include "BKE_preferences.h" # include "BKE_screen.h" # include "DEG_depsgraph.h" @@ -335,6 +336,12 @@ static void rna_userdef_language_update(Main *UNUSED(bmain), USERDEF_TAG_DIRTY; } +static void rna_userdef_asset_library_name_set(PointerRNA *ptr, const char *value) +{ + bUserAssetLibrary *library = (bUserAssetLibrary *)ptr->data; + BKE_preferences_asset_library_name_set(&U, library, value); +} + static void rna_userdef_script_autoexec_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) @@ -4575,7 +4582,7 @@ static void rna_def_userdef_view(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Navigation Controls", - "Show navigation controls in 2D & 3D views which do not have scroll bars"); + "Show navigation controls in 2D and 3D views which do not have scroll bars"); RNA_def_property_update(prop, 0, "rna_userdef_gizmo_update"); /* menus */ @@ -5273,12 +5280,12 @@ static void rna_def_userdef_system(BlenderRNA *brna) }; static const EnumPropertyItem audio_format_items[] = { - {0x01, "U8", 0, "8-bit Unsigned", "Set audio sample format to 8 bit unsigned integer"}, - {0x12, "S16", 0, "16-bit Signed", "Set audio sample format to 16 bit signed integer"}, - {0x13, "S24", 0, "24-bit Signed", "Set audio sample format to 24 bit signed integer"}, - {0x14, "S32", 0, "32-bit Signed", "Set audio sample format to 32 bit signed integer"}, - {0x24, "FLOAT", 0, "32-bit Float", "Set audio sample format to 32 bit float"}, - {0x28, "DOUBLE", 0, "64-bit Float", "Set audio sample format to 64 bit float"}, + {0x01, "U8", 0, "8-bit Unsigned", "Set audio sample format to 8-bit unsigned integer"}, + {0x12, "S16", 0, "16-bit Signed", "Set audio sample format to 16-bit signed integer"}, + {0x13, "S24", 0, "24-bit Signed", "Set audio sample format to 24-bit signed integer"}, + {0x14, "S32", 0, "32-bit Signed", "Set audio sample format to 32-bit signed integer"}, + {0x24, "FLOAT", 0, "32-bit Float", "Set audio sample format to 32-bit float"}, + {0x28, "DOUBLE", 0, "64-bit Float", "Set audio sample format to 64-bit float"}, {0, NULL, 0, NULL, NULL}, }; @@ -5946,12 +5953,6 @@ static void rna_def_userdef_input(BlenderRNA *brna) prop = RNA_def_property(srna, "invert_zoom_wheel", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_WHEELZOOMDIR); RNA_def_property_ui_text(prop, "Wheel Invert Zoom", "Swap the Mouse Wheel zoom direction"); - - prop = RNA_def_property(srna, "wheel_scroll_lines", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "wheellinescroll"); - RNA_def_property_range(prop, 0, 32); - RNA_def_property_ui_text( - prop, "Wheel Scroll Lines", "Number of lines scrolled at a time with the mouse wheel"); } static void rna_def_userdef_keymap(BlenderRNA *brna) @@ -5974,6 +5975,30 @@ static void rna_def_userdef_keymap(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Key Config", "The name of the active key configuration"); } +static void rna_def_userdef_filepaths_asset_library(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "UserAssetLibrary", NULL); + RNA_def_struct_sdna(srna, "bUserAssetLibrary"); + RNA_def_struct_clear_flag(srna, STRUCT_UNDO); + RNA_def_struct_ui_text( + srna, "Asset Library", "Settings to define a reusable library for Asset Browsers to use"); + + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_ui_text( + prop, "Name", "Identifier (not necessarily unique) for the asset library"); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_userdef_asset_library_name_set"); + RNA_def_struct_name_property(srna, prop); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + + prop = RNA_def_property(srna, "path", PROP_STRING, PROP_DIRPATH); + RNA_def_property_ui_text( + prop, "Path", "Path to a directory with .blend files to use as an asset library"); + RNA_def_property_update(prop, 0, "rna_userdef_update"); +} + static void rna_def_userdef_filepaths(BlenderRNA *brna) { PropertyRNA *prop; @@ -5984,7 +6009,7 @@ static void rna_def_userdef_filepaths(BlenderRNA *brna) {2, "DJV", 0, "DJV", "Open source frame player: http://djv.sourceforge.net"}, {3, "FRAMECYCLER", 0, "FrameCycler", "Frame player from IRIDAS"}, {4, "RV", 0, "RV", "Frame player from Tweak Software"}, - {5, "MPLAYER", 0, "MPlayer", "Media player for video & png/jpeg/sgi image sequences"}, + {5, "MPLAYER", 0, "MPlayer", "Media player for video and PNG/JPEG/SGI image sequences"}, {50, "CUSTOM", 0, "Custom", "Custom animation player executable path"}, {0, NULL, 0, NULL, NULL}, }; @@ -6067,10 +6092,11 @@ static void rna_def_userdef_filepaths(BlenderRNA *brna) prop = RNA_def_property(srna, "script_directory", PROP_STRING, PROP_DIRPATH); RNA_def_property_string_sdna(prop, NULL, "pythondir"); - RNA_def_property_ui_text(prop, - "Python Scripts Directory", - "Alternate script path, matching the default layout with subdirs: " - "startup, add-ons & modules (requires restart)"); + RNA_def_property_ui_text( + prop, + "Python Scripts Directory", + "Alternate script path, matching the default layout with subdirectories: " + "startup, add-ons and modules (requires restart)"); /* TODO, editing should reset sys.path! */ prop = RNA_def_property(srna, "i18n_branches_directory", PROP_STRING, PROP_DIRPATH); @@ -6125,7 +6151,7 @@ static void rna_def_userdef_filepaths(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Auto Save Temporary Files", "Automatic saving of temporary files in temp directory, " - "uses process ID (sculpt & edit-mode data won't be saved!)"); + "uses process ID (sculpt and edit mode data won't be saved)"); RNA_def_property_update(prop, 0, "rna_userdef_autosave_update"); prop = RNA_def_property(srna, "auto_save_time", PROP_INT, PROP_NONE); @@ -6145,6 +6171,12 @@ static void rna_def_userdef_filepaths(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Save Preview Images", "Enables automatic saving of preview images in the .blend file"); + + rna_def_userdef_filepaths_asset_library(brna); + + prop = RNA_def_property(srna, "asset_libraries", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "UserAssetLibrary"); + RNA_def_property_ui_text(prop, "Asset Libraries", ""); } static void rna_def_userdef_experimental(BlenderRNA *brna) @@ -6165,6 +6197,11 @@ static void rna_def_userdef_experimental(BlenderRNA *brna) "Undo Legacy", "Use legacy undo (slower than the new default one, but may be more stable in some cases)"); + prop = RNA_def_property(srna, "use_new_point_cloud_type", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "use_new_point_cloud_type", 1); + RNA_def_property_ui_text( + prop, "New Point Cloud Type", "Enable the new point cloud type in the ui"); + prop = RNA_def_property(srna, "use_new_hair_type", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "use_new_hair_type", 1); RNA_def_property_ui_text(prop, "New Hair Type", "Enable the new hair type in the ui"); @@ -6294,7 +6331,7 @@ void RNA_def_userdef(BlenderRNA *brna) prop = RNA_def_property(srna, "autoexec_paths", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "autoexec_paths", NULL); RNA_def_property_struct_type(prop, "PathCompare"); - RNA_def_property_ui_text(prop, "Autoexec Paths", ""); + RNA_def_property_ui_text(prop, "Auto-Execution Paths", ""); rna_def_userdef_autoexec_path_collection(brna, prop); /* nested structs */ diff --git a/source/blender/makesrna/intern/rna_volume.c b/source/blender/makesrna/intern/rna_volume.c index 37b34f68be5..42d491b734e 100644 --- a/source/blender/makesrna/intern/rna_volume.c +++ b/source/blender/makesrna/intern/rna_volume.c @@ -228,8 +228,8 @@ static void rna_def_volume_grid(BlenderRNA *brna) {VOLUME_GRID_BOOLEAN, "BOOLEAN", 0, "Boolean", "Boolean"}, {VOLUME_GRID_FLOAT, "FLOAT", 0, "Float", "Single precision float"}, {VOLUME_GRID_DOUBLE, "DOUBLE", 0, "Double", "Double precision"}, - {VOLUME_GRID_INT, "INT", 0, "Integer", "32 bit integer"}, - {VOLUME_GRID_INT64, "INT64", 0, "Integer 64 bit", "64 bit integer"}, + {VOLUME_GRID_INT, "INT", 0, "Integer", "32-bit integer"}, + {VOLUME_GRID_INT64, "INT64", 0, "Integer 64-bit", "64-bit integer"}, {VOLUME_GRID_MASK, "MASK", 0, "Mask", "No data, boolean mask of active voxels"}, {VOLUME_GRID_STRING, "STRING", 0, "String", "Text string"}, {VOLUME_GRID_VECTOR_FLOAT, "VECTOR_FLOAT", 0, "Float Vector", "3D float vector"}, diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt index 26f31412724..3a7addcba94 100644 --- a/source/blender/modifiers/CMakeLists.txt +++ b/source/blender/modifiers/CMakeLists.txt @@ -78,6 +78,7 @@ set(SRC intern/MOD_meshsequencecache.c intern/MOD_mirror.c intern/MOD_multires.c + intern/MOD_nodes.cc intern/MOD_none.c intern/MOD_normal_edit.c intern/MOD_ocean.c @@ -88,7 +89,6 @@ set(SRC intern/MOD_shapekey.c intern/MOD_shrinkwrap.c intern/MOD_simpledeform.c - intern/MOD_nodes.cc intern/MOD_skin.c intern/MOD_smooth.c intern/MOD_softbody.c @@ -199,6 +199,7 @@ endif() if(WITH_EXPERIMENTAL_FEATURES) add_definitions(-DWITH_GEOMETRY_NODES) + add_definitions(-DWITH_POINT_CLOUD) add_definitions(-DWITH_HAIR_NODES) endif() diff --git a/source/blender/modifiers/MOD_nodes.h b/source/blender/modifiers/MOD_nodes.h index 9c75e7e3416..907dbe9c5f4 100644 --- a/source/blender/modifiers/MOD_nodes.h +++ b/source/blender/modifiers/MOD_nodes.h @@ -17,8 +17,8 @@ #pragma once struct Main; -struct Object; struct NodesModifierData; +struct Object; #ifdef __cplusplus extern "C" { diff --git a/source/blender/modifiers/intern/MOD_armature.c b/source/blender/modifiers/intern/MOD_armature.c index 38fb19e3233..6769f14f88f 100644 --- a/source/blender/modifiers/intern/MOD_armature.c +++ b/source/blender/modifiers/intern/MOD_armature.c @@ -295,7 +295,7 @@ ModifierTypeInfo modifierType_Armature = { /* deformMatricesEM */ deformMatricesEM, /* modifyMesh */ NULL, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c index da1754b8ebd..412d6b87d82 100644 --- a/source/blender/modifiers/intern/MOD_array.c +++ b/source/blender/modifiers/intern/MOD_array.c @@ -1018,7 +1018,7 @@ ModifierTypeInfo modifierType_Array = { /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c index aa97887fe31..3a4287ce35a 100644 --- a/source/blender/modifiers/intern/MOD_bevel.c +++ b/source/blender/modifiers/intern/MOD_bevel.c @@ -447,7 +447,7 @@ ModifierTypeInfo modifierType_Bevel = { /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, /* requiredDataMask */ requiredDataMask, diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c index b1bf4067e18..66ccffd53b1 100644 --- a/source/blender/modifiers/intern/MOD_boolean.c +++ b/source/blender/modifiers/intern/MOD_boolean.c @@ -824,7 +824,7 @@ ModifierTypeInfo modifierType_Boolean = { /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_build.c b/source/blender/modifiers/intern/MOD_build.c index 96ed0a5d069..0b1c661baed 100644 --- a/source/blender/modifiers/intern/MOD_build.c +++ b/source/blender/modifiers/intern/MOD_build.c @@ -346,7 +346,7 @@ ModifierTypeInfo modifierType_Build = { /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_cast.c b/source/blender/modifiers/intern/MOD_cast.c index 06bd9ada0fb..f905a38ae12 100644 --- a/source/blender/modifiers/intern/MOD_cast.c +++ b/source/blender/modifiers/intern/MOD_cast.c @@ -590,7 +590,7 @@ ModifierTypeInfo modifierType_Cast = { /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_cloth.c b/source/blender/modifiers/intern/MOD_cloth.c index 8f876213cd6..a25d65347c5 100644 --- a/source/blender/modifiers/intern/MOD_cloth.c +++ b/source/blender/modifiers/intern/MOD_cloth.c @@ -33,6 +33,7 @@ #include "DNA_defaults.h" #include "DNA_key_types.h" #include "DNA_mesh_types.h" +#include "DNA_object_force_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" @@ -116,7 +117,7 @@ static void deformVerts(ModifierData *md, mesh_src = (Mesh *)BKE_id_copy_ex(NULL, (ID *)mesh, NULL, LIB_ID_COPY_LOCALIZE); } - /* TODO(sergey): For now it actually duplicates logic from DerivedMesh.c + /* TODO(sergey): For now it actually duplicates logic from DerivedMesh.cc * and needs some more generic solution. But starting experimenting with * this so close to the release is not that nice.. * @@ -309,7 +310,7 @@ ModifierTypeInfo modifierType_Cloth = { /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c index faba08f9613..a80bac7c6de 100644 --- a/source/blender/modifiers/intern/MOD_collision.c +++ b/source/blender/modifiers/intern/MOD_collision.c @@ -23,6 +23,7 @@ #include "BLI_utildefines.h" +#include "BLI_kdopbvh.h" #include "BLI_math.h" #include "BLT_translation.h" @@ -30,6 +31,7 @@ #include "DNA_defaults.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "DNA_object_force_types.h" #include "DNA_object_types.h" #include "DNA_screen_types.h" @@ -309,7 +311,7 @@ ModifierTypeInfo modifierType_Collision = { /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_correctivesmooth.c b/source/blender/modifiers/intern/MOD_correctivesmooth.c index 5884ec0aa17..15c4e8af6ce 100644 --- a/source/blender/modifiers/intern/MOD_correctivesmooth.c +++ b/source/blender/modifiers/intern/MOD_correctivesmooth.c @@ -851,7 +851,7 @@ ModifierTypeInfo modifierType_CorrectiveSmooth = { /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_curve.c b/source/blender/modifiers/intern/MOD_curve.c index bed53cb0f51..d5d53edfd54 100644 --- a/source/blender/modifiers/intern/MOD_curve.c +++ b/source/blender/modifiers/intern/MOD_curve.c @@ -235,7 +235,7 @@ ModifierTypeInfo modifierType_Curve = { /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_datatransfer.c b/source/blender/modifiers/intern/MOD_datatransfer.c index d4c941d144d..8b299a82f95 100644 --- a/source/blender/modifiers/intern/MOD_datatransfer.c +++ b/source/blender/modifiers/intern/MOD_datatransfer.c @@ -494,7 +494,7 @@ ModifierTypeInfo modifierType_DataTransfer = { /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c index 5e6d25cf55d..8f9da001757 100644 --- a/source/blender/modifiers/intern/MOD_decimate.c +++ b/source/blender/modifiers/intern/MOD_decimate.c @@ -300,7 +300,7 @@ ModifierTypeInfo modifierType_Decimate = { /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c index d432559fcfa..5359736d9fc 100644 --- a/source/blender/modifiers/intern/MOD_displace.c +++ b/source/blender/modifiers/intern/MOD_displace.c @@ -437,7 +437,7 @@ static void panel_draw(const bContext *C, Panel *panel) uiLayoutSetPropSep(layout, true); - uiTemplateID(layout, C, ptr, "texture", "texture.new", NULL, NULL, 0, ICON_NONE, NULL); + uiTemplateID(layout, C, ptr, "texture", "texture.new", NULL, NULL, NULL, 0, ICON_NONE, NULL); col = uiLayoutColumn(layout, false); uiLayoutSetActive(col, has_texture); @@ -506,7 +506,7 @@ ModifierTypeInfo modifierType_Displace = { /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_dynamicpaint.c b/source/blender/modifiers/intern/MOD_dynamicpaint.c index b69179f464d..7f57183ff13 100644 --- a/source/blender/modifiers/intern/MOD_dynamicpaint.c +++ b/source/blender/modifiers/intern/MOD_dynamicpaint.c @@ -220,7 +220,7 @@ ModifierTypeInfo modifierType_DynamicPaint = { /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c index 2614b0d719f..5e9a51adc36 100644 --- a/source/blender/modifiers/intern/MOD_edgesplit.c +++ b/source/blender/modifiers/intern/MOD_edgesplit.c @@ -187,7 +187,7 @@ ModifierTypeInfo modifierType_EdgeSplit = { /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c index d5e065ad321..c12019a325e 100644 --- a/source/blender/modifiers/intern/MOD_explode.c +++ b/source/blender/modifiers/intern/MOD_explode.c @@ -1254,7 +1254,7 @@ ModifierTypeInfo modifierType_Explode = { /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_fluid.c b/source/blender/modifiers/intern/MOD_fluid.c index 6dc4fe79f88..8a8d6f2305f 100644 --- a/source/blender/modifiers/intern/MOD_fluid.c +++ b/source/blender/modifiers/intern/MOD_fluid.c @@ -238,7 +238,7 @@ ModifierTypeInfo modifierType_Fluid = { /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c index e0c362171f2..2fa05a319d5 100644 --- a/source/blender/modifiers/intern/MOD_hook.c +++ b/source/blender/modifiers/intern/MOD_hook.c @@ -573,7 +573,7 @@ ModifierTypeInfo modifierType_Hook = { /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_laplaciandeform.c b/source/blender/modifiers/intern/MOD_laplaciandeform.c index a484b4d8147..bda0f9ba5a4 100644 --- a/source/blender/modifiers/intern/MOD_laplaciandeform.c +++ b/source/blender/modifiers/intern/MOD_laplaciandeform.c @@ -888,7 +888,7 @@ ModifierTypeInfo modifierType_LaplacianDeform = { /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_laplaciansmooth.c b/source/blender/modifiers/intern/MOD_laplaciansmooth.c index d51f95bd18d..fc527304e76 100644 --- a/source/blender/modifiers/intern/MOD_laplaciansmooth.c +++ b/source/blender/modifiers/intern/MOD_laplaciansmooth.c @@ -634,7 +634,7 @@ ModifierTypeInfo modifierType_LaplacianSmooth = { /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ init_data, diff --git a/source/blender/modifiers/intern/MOD_lattice.c b/source/blender/modifiers/intern/MOD_lattice.c index 5aadc171394..e3c42e39dda 100644 --- a/source/blender/modifiers/intern/MOD_lattice.c +++ b/source/blender/modifiers/intern/MOD_lattice.c @@ -192,7 +192,7 @@ ModifierTypeInfo modifierType_Lattice = { /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_mask.cc b/source/blender/modifiers/intern/MOD_mask.cc index 92ee5a84df9..191d39d9fce 100644 --- a/source/blender/modifiers/intern/MOD_mask.cc +++ b/source/blender/modifiers/intern/MOD_mask.cc @@ -462,7 +462,7 @@ ModifierTypeInfo modifierType_Mask = { /* deformMatricesEM */ nullptr, /* modifyMesh */ modifyMesh, /* modifyHair */ nullptr, - /* modifyPointCloud */ nullptr, + /* modifyGeometrySet */ nullptr, /* modifyVolume */ nullptr, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_mesh_to_volume.cc b/source/blender/modifiers/intern/MOD_mesh_to_volume.cc index e137a59e10f..cc007651733 100644 --- a/source/blender/modifiers/intern/MOD_mesh_to_volume.cc +++ b/source/blender/modifiers/intern/MOD_mesh_to_volume.cc @@ -295,7 +295,7 @@ ModifierTypeInfo modifierType_MeshToVolume = { /* deformMatricesEM */ nullptr, /* modifyMesh */ nullptr, /* modifyHair */ nullptr, - /* modifyPointCloud */ nullptr, + /* modifyGeometrySet */ nullptr, /* modifyVolume */ modifyVolume, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_meshcache.c b/source/blender/modifiers/intern/MOD_meshcache.c index b808d738fe8..6d2e0f242d7 100644 --- a/source/blender/modifiers/intern/MOD_meshcache.c +++ b/source/blender/modifiers/intern/MOD_meshcache.c @@ -388,7 +388,7 @@ ModifierTypeInfo modifierType_MeshCache = { /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c index 0e530312238..4bd306e7679 100644 --- a/source/blender/modifiers/intern/MOD_meshdeform.c +++ b/source/blender/modifiers/intern/MOD_meshdeform.c @@ -646,7 +646,7 @@ ModifierTypeInfo modifierType_MeshDeform = { /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c index 73106b2e816..2c01857adb1 100644 --- a/source/blender/modifiers/intern/MOD_meshsequencecache.c +++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c @@ -270,7 +270,7 @@ ModifierTypeInfo modifierType_MeshSequenceCache = { /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c index 9346f601981..7f34c6581ad 100644 --- a/source/blender/modifiers/intern/MOD_mirror.c +++ b/source/blender/modifiers/intern/MOD_mirror.c @@ -234,7 +234,7 @@ ModifierTypeInfo modifierType_Mirror = { /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c index 9f99e036601..1182c8db093 100644 --- a/source/blender/modifiers/intern/MOD_multires.c +++ b/source/blender/modifiers/intern/MOD_multires.c @@ -519,7 +519,7 @@ ModifierTypeInfo modifierType_Multires = { /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index 80c69398d15..133a19dde9e 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -33,6 +33,7 @@ #include "BLI_string.h" #include "BLI_utildefines.h" +#include "DNA_collection_types.h" #include "DNA_defaults.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -104,6 +105,12 @@ static void addIdsUsedBySocket(const ListBase *sockets, Set<ID *> &ids) ids.add(&object->id); } } + else if (socket->type == SOCK_COLLECTION) { + Collection *collection = ((bNodeSocketValueCollection *)socket->default_value)->value; + if (collection != nullptr) { + ids.add(&collection->id); + } + } } } @@ -147,6 +154,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte } /* TODO: Add relations for IDs in settings. */ + /* TODO: Add dependency for collection changes. */ } static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData) @@ -293,13 +301,28 @@ class GeometryNodesEvaluator { void execute_node(const DNode &node, GeoNodeExecParams params) { const bNode &bnode = params.node(); + + /* Use the geometry-node-execute callback if it exists. */ if (bnode.typeinfo->geometry_node_execute != nullptr) { bnode.typeinfo->geometry_node_execute(params); return; } - /* Use the multi-function implementation of the node. */ - const MultiFunction &fn = *mf_by_node_.lookup(&node); + /* Use the multi-function implementation if it exists. */ + const MultiFunction *multi_function = mf_by_node_.lookup_default(&node, nullptr); + if (multi_function != nullptr) { + this->execute_multi_function_node(node, params, *multi_function); + return; + } + + /* Just output default values if no implementation exists. */ + this->execute_unknown_node(node, params); + } + + void execute_multi_function_node(const DNode &node, + GeoNodeExecParams params, + const MultiFunction &fn) + { MFContextBuilder fn_context; MFParamsBuilder fn_params{fn, 1}; Vector<GMutablePointer> input_data; @@ -334,6 +357,16 @@ class GeometryNodesEvaluator { } } + void execute_unknown_node(const DNode &node, GeoNodeExecParams params) + { + for (const DOutputSocket *socket : node.outputs()) { + if (socket->is_available()) { + const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket->typeinfo()); + params.set_output_by_copy(socket->identifier(), {type, type.default_value()}); + } + } + } + void forward_to_inputs(const DOutputSocket &from_socket, GMutablePointer value_to_forward) { Span<const DInputSocket *> to_sockets_all = from_socket.linked_sockets(); @@ -399,6 +432,11 @@ class GeometryNodesEvaluator { blender::bke::PersistentObjectHandle object_handle = handle_map_.lookup(object); new (buffer) blender::bke::PersistentObjectHandle(object_handle); } + else if (bsocket->type == SOCK_COLLECTION) { + Collection *collection = ((bNodeSocketValueCollection *)bsocket->default_value)->value; + blender::bke::PersistentCollectionHandle collection_handle = handle_map_.lookup(collection); + new (buffer) blender::bke::PersistentCollectionHandle(collection_handle); + } else { blender::nodes::socket_cpp_value_get(*bsocket, buffer); } @@ -439,6 +477,8 @@ static IDProperty *socket_add_property(IDProperty *settings_prop_group, IDProperty *prop = property_type.create_prop(socket, new_prop_name); IDP_AddToGroup(settings_prop_group, prop); + prop->flag |= IDP_FLAG_OVERRIDABLE_LIBRARY; + /* Make the group in the ui container group to hold the property's UI settings. */ IDProperty *prop_ui_group; { @@ -848,6 +888,9 @@ static void check_property_socket_sync(const Object *ob, ModifierData *md) else if (socket->type == SOCK_GEOMETRY) { BKE_modifier_set_error(ob, md, "Node group can only have one geometry input"); } + else if (socket->type == SOCK_COLLECTION) { + BKE_modifier_set_error(ob, md, "Collection socket can not be exposed in the modifier"); + } else { BKE_modifier_set_error(ob, md, "Missing property for input socket \"%s\"", socket->name); } @@ -934,9 +977,9 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * return new_mesh; } -static void modifyPointCloud(ModifierData *md, - const ModifierEvalContext *ctx, - GeometrySet *geometry_set) +static void modifyGeometrySet(ModifierData *md, + const ModifierEvalContext *ctx, + GeometrySet *geometry_set) { modifyGeometry(md, ctx, *geometry_set); } @@ -960,8 +1003,12 @@ static void draw_property_for_socket(uiLayout *layout, /* IDProperties can be removed with python, so there could be a situation where * there isn't a property for a socket or it doesn't have the correct type. */ if (property != nullptr && property_type->is_correct_type(*property)) { - char rna_path[128]; - BLI_snprintf(rna_path, ARRAY_SIZE(rna_path), "[\"%s\"]", socket.identifier); + + char socket_id_esc[sizeof(socket.identifier) * 2]; + BLI_str_escape(socket_id_esc, socket.identifier, sizeof(socket_id_esc)); + + char rna_path[sizeof(socket_id_esc) + 4]; + BLI_snprintf(rna_path, ARRAY_SIZE(rna_path), "[\"%s\"]", socket_id_esc); uiItemR(layout, settings_ptr, rna_path, 0, socket.name, ICON_NONE); } } @@ -984,6 +1031,7 @@ static void panel_draw(const bContext *C, Panel *panel) "node.new_geometry_node_group_assign", nullptr, nullptr, + nullptr, 0, false, nullptr); @@ -1043,6 +1091,15 @@ static void freeData(ModifierData *md) } } +static void requiredDataMask(Object *UNUSED(ob), + ModifierData *UNUSED(md), + CustomData_MeshMasks *r_cddata_masks) +{ + /* We don't know what the node tree will need. If there are vertex groups, it is likely that the + * node tree wants to access them. */ + r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; +} + ModifierTypeInfo modifierType_Nodes = { /* name */ "GeometryNodes", /* structName */ "NodesModifierData", @@ -1050,9 +1107,9 @@ ModifierTypeInfo modifierType_Nodes = { /* srna */ &RNA_NodesModifier, /* type */ eModifierTypeType_Constructive, /* flags */ - static_cast<ModifierTypeFlag>(eModifierTypeFlag_AcceptsMesh | - eModifierTypeFlag_SupportsEditmode | - eModifierTypeFlag_EnableInEditmode), + static_cast<ModifierTypeFlag>( + eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsEditmode | + eModifierTypeFlag_EnableInEditmode | eModifierTypeFlag_SupportsMapping), /* icon */ ICON_NODETREE, /* copyData */ copyData, @@ -1063,11 +1120,11 @@ ModifierTypeInfo modifierType_Nodes = { /* deformMatricesEM */ nullptr, /* modifyMesh */ modifyMesh, /* modifyHair */ nullptr, - /* modifyPointCloud */ modifyPointCloud, + /* modifyGeometrySet */ modifyGeometrySet, /* modifyVolume */ nullptr, /* initData */ initData, - /* requiredDataMask */ nullptr, + /* requiredDataMask */ requiredDataMask, /* freeData */ freeData, /* isDisabled */ isDisabled, /* updateDepsgraph */ updateDepsgraph, diff --git a/source/blender/modifiers/intern/MOD_none.c b/source/blender/modifiers/intern/MOD_none.c index 02307622d06..4daa527577b 100644 --- a/source/blender/modifiers/intern/MOD_none.c +++ b/source/blender/modifiers/intern/MOD_none.c @@ -59,7 +59,7 @@ ModifierTypeInfo modifierType_None = { /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ NULL, diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c index 0ec564d2e2d..ec10b18665e 100644 --- a/source/blender/modifiers/intern/MOD_normal_edit.c +++ b/source/blender/modifiers/intern/MOD_normal_edit.c @@ -804,7 +804,7 @@ ModifierTypeInfo modifierType_NormalEdit = { /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c index 5aef497c0c4..9c940745920 100644 --- a/source/blender/modifiers/intern/MOD_ocean.c +++ b/source/blender/modifiers/intern/MOD_ocean.c @@ -736,7 +736,7 @@ ModifierTypeInfo modifierType_Ocean = { /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c index f660874a5ea..e7f1fa9943e 100644 --- a/source/blender/modifiers/intern/MOD_particleinstance.c +++ b/source/blender/modifiers/intern/MOD_particleinstance.c @@ -678,7 +678,7 @@ ModifierTypeInfo modifierType_ParticleInstance = { /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.c index b82474e1a86..88f1a7cb034 100644 --- a/source/blender/modifiers/intern/MOD_particlesystem.c +++ b/source/blender/modifiers/intern/MOD_particlesystem.c @@ -331,7 +331,7 @@ ModifierTypeInfo modifierType_ParticleSystem = { /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_remesh.c b/source/blender/modifiers/intern/MOD_remesh.c index f8fc4ad658e..175435fcd44 100644 --- a/source/blender/modifiers/intern/MOD_remesh.c +++ b/source/blender/modifiers/intern/MOD_remesh.c @@ -300,7 +300,7 @@ ModifierTypeInfo modifierType_Remesh = { /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c index 6521a0859e5..ba370b401f3 100644 --- a/source/blender/modifiers/intern/MOD_screw.c +++ b/source/blender/modifiers/intern/MOD_screw.c @@ -701,8 +701,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * /*printf("flip direction %i\n", ed_loop_flip);*/ - /* switch the flip option if set - * note: flip is now done at face level so copying vgroup slizes is easier */ + /* Switch the flip option if set + * NOTE: flip is now done at face level so copying group slices is easier. */ #if 0 if (do_flip) { ed_loop_flip = !ed_loop_flip; @@ -1259,7 +1259,7 @@ ModifierTypeInfo modifierType_Screw = { /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_shapekey.c b/source/blender/modifiers/intern/MOD_shapekey.c index bb267386dfb..81a0ee72496 100644 --- a/source/blender/modifiers/intern/MOD_shapekey.c +++ b/source/blender/modifiers/intern/MOD_shapekey.c @@ -27,6 +27,7 @@ #include "DNA_key_types.h" #include "DNA_mesh_types.h" +#include "DNA_object_types.h" #include "BKE_key.h" #include "BKE_particle.h" @@ -139,7 +140,7 @@ ModifierTypeInfo modifierType_ShapeKey = { /* deformMatricesEM */ deformMatricesEM, /* modifyMesh */ NULL, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ NULL, diff --git a/source/blender/modifiers/intern/MOD_shrinkwrap.c b/source/blender/modifiers/intern/MOD_shrinkwrap.c index dddabb12f61..93626309727 100644 --- a/source/blender/modifiers/intern/MOD_shrinkwrap.c +++ b/source/blender/modifiers/intern/MOD_shrinkwrap.c @@ -292,7 +292,7 @@ ModifierTypeInfo modifierType_Shrinkwrap = { /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_simpledeform.c b/source/blender/modifiers/intern/MOD_simpledeform.c index ec89176f97e..e41e70864dc 100644 --- a/source/blender/modifiers/intern/MOD_simpledeform.c +++ b/source/blender/modifiers/intern/MOD_simpledeform.c @@ -552,7 +552,7 @@ ModifierTypeInfo modifierType_SimpleDeform = { /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c index 6936f5a53f8..5e412185cea 100644 --- a/source/blender/modifiers/intern/MOD_skin.c +++ b/source/blender/modifiers/intern/MOD_skin.c @@ -2043,7 +2043,7 @@ ModifierTypeInfo modifierType_Skin = { /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_smooth.c b/source/blender/modifiers/intern/MOD_smooth.c index e73a59f1ae8..618ccc78279 100644 --- a/source/blender/modifiers/intern/MOD_smooth.c +++ b/source/blender/modifiers/intern/MOD_smooth.c @@ -32,6 +32,7 @@ #include "DNA_defaults.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "DNA_object_types.h" #include "DNA_screen_types.h" #include "BKE_context.h" @@ -286,7 +287,7 @@ ModifierTypeInfo modifierType_Smooth = { /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_softbody.c b/source/blender/modifiers/intern/MOD_softbody.c index 4bdb3ba60b1..9a657c44fca 100644 --- a/source/blender/modifiers/intern/MOD_softbody.c +++ b/source/blender/modifiers/intern/MOD_softbody.c @@ -119,7 +119,7 @@ ModifierTypeInfo modifierType_Softbody = { /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ NULL, diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c index 8886d3718c9..8e519a72df1 100644 --- a/source/blender/modifiers/intern/MOD_solidify.c +++ b/source/blender/modifiers/intern/MOD_solidify.c @@ -29,6 +29,7 @@ #include "DNA_defaults.h" #include "DNA_mesh_types.h" +#include "DNA_object_types.h" #include "DNA_screen_types.h" #include "BKE_context.h" @@ -274,7 +275,7 @@ ModifierTypeInfo modifierType_Solidify = { /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_solidify_extrude.c b/source/blender/modifiers/intern/MOD_solidify_extrude.c index c8b357b34c8..99069919120 100644 --- a/source/blender/modifiers/intern/MOD_solidify_extrude.c +++ b/source/blender/modifiers/intern/MOD_solidify_extrude.c @@ -26,6 +26,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "DNA_object_types.h" #include "MEM_guardedalloc.h" diff --git a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c index 8acf07f9181..f62980ec4fd 100644 --- a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c +++ b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c @@ -24,6 +24,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "DNA_object_types.h" #include "MEM_guardedalloc.h" diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c index 1aa015682dd..d089894a6e9 100644 --- a/source/blender/modifiers/intern/MOD_subsurf.c +++ b/source/blender/modifiers/intern/MOD_subsurf.c @@ -507,7 +507,7 @@ ModifierTypeInfo modifierType_Subsurf = { /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_surface.c b/source/blender/modifiers/intern/MOD_surface.c index 72f19efe3a4..7416a4baf38 100644 --- a/source/blender/modifiers/intern/MOD_surface.c +++ b/source/blender/modifiers/intern/MOD_surface.c @@ -240,7 +240,7 @@ ModifierTypeInfo modifierType_Surface = { /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_surfacedeform.c b/source/blender/modifiers/intern/MOD_surfacedeform.c index 5407397e3bf..e00c5ba7f04 100644 --- a/source/blender/modifiers/intern/MOD_surfacedeform.c +++ b/source/blender/modifiers/intern/MOD_surfacedeform.c @@ -1546,7 +1546,7 @@ ModifierTypeInfo modifierType_SurfaceDeform = { /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_triangulate.c b/source/blender/modifiers/intern/MOD_triangulate.c index 1c92d19c68d..6d5fe17104c 100644 --- a/source/blender/modifiers/intern/MOD_triangulate.c +++ b/source/blender/modifiers/intern/MOD_triangulate.c @@ -177,7 +177,7 @@ ModifierTypeInfo modifierType_Triangulate = { /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_ui_common.c b/source/blender/modifiers/intern/MOD_ui_common.c index fa5243c548f..55dbfdf478f 100644 --- a/source/blender/modifiers/intern/MOD_ui_common.c +++ b/source/blender/modifiers/intern/MOD_ui_common.c @@ -307,10 +307,16 @@ static void modifier_panel_header(const bContext *C, Panel *panel) /* Modifier Icon. */ sub = uiLayoutRow(layout, true); + uiLayoutSetEmboss(sub, UI_EMBOSS_NONE); if (mti->isDisabled && mti->isDisabled(scene, md, 0)) { uiLayoutSetRedAlert(sub, true); } - uiItemL(sub, "", RNA_struct_ui_icon(ptr->type)); + uiItemStringO(sub, + "", + RNA_struct_ui_icon(ptr->type), + "OBJECT_OT_modifier_set_active", + "modifier", + md->name); row = uiLayoutRow(layout, true); diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c index bfbc27abb88..8122f4617c1 100644 --- a/source/blender/modifiers/intern/MOD_uvproject.c +++ b/source/blender/modifiers/intern/MOD_uvproject.c @@ -370,7 +370,7 @@ ModifierTypeInfo modifierType_UVProject = { /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_uvwarp.c b/source/blender/modifiers/intern/MOD_uvwarp.c index 10b011360b6..cc845854956 100644 --- a/source/blender/modifiers/intern/MOD_uvwarp.c +++ b/source/blender/modifiers/intern/MOD_uvwarp.c @@ -357,7 +357,7 @@ ModifierTypeInfo modifierType_UVWarp = { /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_volume_displace.cc b/source/blender/modifiers/intern/MOD_volume_displace.cc index 90e570f55fb..a916eff6617 100644 --- a/source/blender/modifiers/intern/MOD_volume_displace.cc +++ b/source/blender/modifiers/intern/MOD_volume_displace.cc @@ -113,7 +113,8 @@ static void panel_draw(const bContext *C, Panel *panel) uiLayoutSetPropSep(layout, true); - uiTemplateID(layout, C, ptr, "texture", "texture.new", nullptr, nullptr, 0, ICON_NONE, nullptr); + uiTemplateID( + layout, C, ptr, "texture", "texture.new", nullptr, nullptr, nullptr, 0, ICON_NONE, nullptr); uiItemR(layout, ptr, "texture_map_mode", 0, "Texture Mapping", ICON_NONE); if (vdmd->texture_map_mode == MOD_VOLUME_DISPLACE_MAP_OBJECT) { @@ -328,7 +329,7 @@ ModifierTypeInfo modifierType_VolumeDisplace = { /* deformMatricesEM */ nullptr, /* modifyMesh */ nullptr, /* modifyHair */ nullptr, - /* modifyPointCloud */ nullptr, + /* modifyGeometrySet */ nullptr, /* modifyVolume */ modifyVolume, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_volume_to_mesh.cc b/source/blender/modifiers/intern/MOD_volume_to_mesh.cc index ec53914f115..941bc8409f7 100644 --- a/source/blender/modifiers/intern/MOD_volume_to_mesh.cc +++ b/source/blender/modifiers/intern/MOD_volume_to_mesh.cc @@ -335,7 +335,7 @@ ModifierTypeInfo modifierType_VolumeToMesh = { /* deformMatricesEM */ nullptr, /* modifyMesh */ modifyMesh, /* modifyHair */ nullptr, - /* modifyPointCloud */ nullptr, + /* modifyGeometrySet */ nullptr, /* modifyVolume */ nullptr, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_warp.c b/source/blender/modifiers/intern/MOD_warp.c index 53e41484606..8ad15edff93 100644 --- a/source/blender/modifiers/intern/MOD_warp.c +++ b/source/blender/modifiers/intern/MOD_warp.c @@ -466,7 +466,17 @@ static void texture_panel_draw(const bContext *C, Panel *panel) int texture_coords = RNA_enum_get(ptr, "texture_coords"); - uiTemplateID(layout, C, ptr, "texture", "texture.new", NULL, NULL, 0, ICON_NONE, NULL); + uiTemplateID(layout, + C, + ptr, + "texture", + "texture.new", + "texture.duplicate", + NULL, + NULL, + 0, + ICON_NONE, + NULL); uiLayoutSetPropSep(layout, true); @@ -538,7 +548,7 @@ ModifierTypeInfo modifierType_Warp = { /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c index 45f06a7778c..94d8a80f2b4 100644 --- a/source/blender/modifiers/intern/MOD_wave.c +++ b/source/blender/modifiers/intern/MOD_wave.c @@ -436,7 +436,17 @@ static void texture_panel_draw(const bContext *C, Panel *panel) int texture_coords = RNA_enum_get(ptr, "texture_coords"); - uiTemplateID(layout, C, ptr, "texture", "texture.new", NULL, NULL, 0, ICON_NONE, NULL); + uiTemplateID(layout, + C, + ptr, + "texture", + "texture.new", + "texture.duplicate", + NULL, + NULL, + 0, + ICON_NONE, + NULL); uiLayoutSetPropSep(layout, true); @@ -491,7 +501,7 @@ ModifierTypeInfo modifierType_Wave = { /* deformMatricesEM */ NULL, /* modifyMesh */ NULL, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.c b/source/blender/modifiers/intern/MOD_weighted_normal.c index bd15d909834..40265e37db9 100644 --- a/source/blender/modifiers/intern/MOD_weighted_normal.c +++ b/source/blender/modifiers/intern/MOD_weighted_normal.c @@ -763,7 +763,7 @@ ModifierTypeInfo modifierType_WeightedNormal = { /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_weightvg_util.c b/source/blender/modifiers/intern/MOD_weightvg_util.c index c5e2ecb9660..26b29100d30 100644 --- a/source/blender/modifiers/intern/MOD_weightvg_util.c +++ b/source/blender/modifiers/intern/MOD_weightvg_util.c @@ -363,6 +363,7 @@ void weightvg_ui_common(const bContext *C, PointerRNA *ob_ptr, PointerRNA *ptr, ptr, "mask_texture", "texture.new", + "texture.duplicate", NULL, NULL, 0, diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c index df554f6bc4e..915adccc745 100644 --- a/source/blender/modifiers/intern/MOD_weightvgedit.c +++ b/source/blender/modifiers/intern/MOD_weightvgedit.c @@ -427,7 +427,7 @@ ModifierTypeInfo modifierType_WeightVGEdit = { /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c index 9be36fe6846..52cee7ce7e5 100644 --- a/source/blender/modifiers/intern/MOD_weightvgmix.c +++ b/source/blender/modifiers/intern/MOD_weightvgmix.c @@ -513,7 +513,7 @@ ModifierTypeInfo modifierType_WeightVGMix = { /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c index 7232ffd3d9d..aac29cabf0f 100644 --- a/source/blender/modifiers/intern/MOD_weightvgproximity.c +++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c @@ -767,7 +767,7 @@ ModifierTypeInfo modifierType_WeightVGProximity = { /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_weld.c b/source/blender/modifiers/intern/MOD_weld.c index 1a25c24fedc..fd1254fc948 100644 --- a/source/blender/modifiers/intern/MOD_weld.c +++ b/source/blender/modifiers/intern/MOD_weld.c @@ -1567,6 +1567,12 @@ static bool bvhtree_weld_overlap_cb(void *userdata, int index_a, int index_b, in } #endif +/** Use for #MOD_WELD_MODE_CONNECTED calculation. */ +struct WeldVertexCluster { + float co[3]; + uint merged_verts; +}; + static Mesh *weldModifier_doWeld(WeldModifierData *wmd, const ModifierEvalContext *ctx, Mesh *mesh) { Mesh *result = mesh; @@ -1606,6 +1612,7 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd, const ModifierEvalContex * This indicates which vert it is or is going to be merged. */ uint *vert_dest_map = MEM_malloc_arrayN(totvert, sizeof(*vert_dest_map), __func__); uint vert_kill_len = 0; + if (wmd->mode == MOD_WELD_MODE_ALL) #ifdef USE_BVHTREEKDOP { /* Get overlap map. */ @@ -1701,6 +1708,80 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd, const ModifierEvalContex BLI_kdtree_3d_free(tree); } #endif + else { + BLI_assert(wmd->mode == MOD_WELD_MODE_CONNECTED); + + MEdge *medge, *me; + + medge = mesh->medge; + totvert = mesh->totvert; + totedge = mesh->totedge; + + struct WeldVertexCluster *vert_clusters = MEM_malloc_arrayN( + totvert, sizeof(*vert_clusters), __func__); + struct WeldVertexCluster *vc = &vert_clusters[0]; + for (uint i = 0; i < totvert; i++, vc++) { + copy_v3_v3(vc->co, mvert[i].co); + vc->merged_verts = 0; + } + const float merge_dist_sq = square_f(wmd->merge_dist); + + range_vn_u(vert_dest_map, totvert, 0); + + /* Collapse Edges that are shorter than the threshold. */ + me = &medge[0]; + for (uint i = 0; i < totedge; i++, me++) { + uint v1 = me->v1; + uint v2 = me->v2; + + while (v1 != vert_dest_map[v1]) { + v1 = vert_dest_map[v1]; + } + while (v2 != vert_dest_map[v2]) { + v2 = vert_dest_map[v2]; + } + if (v1 == v2) { + continue; + } + if (v_mask && (!BLI_BITMAP_TEST(v_mask, v1) || !BLI_BITMAP_TEST(v_mask, v2))) { + continue; + } + if (v1 > v2) { + SWAP(uint, v1, v2); + } + struct WeldVertexCluster *v1_cluster = &vert_clusters[v1]; + struct WeldVertexCluster *v2_cluster = &vert_clusters[v2]; + + float edgedir[3]; + sub_v3_v3v3(edgedir, v2_cluster->co, v1_cluster->co); + const float dist_sq = len_squared_v3(edgedir); + if (dist_sq <= merge_dist_sq) { + float influence = (v2_cluster->merged_verts + 1) / + (float)(v1_cluster->merged_verts + v2_cluster->merged_verts + 2); + madd_v3_v3fl(v1_cluster->co, edgedir, influence); + + v1_cluster->merged_verts += v2_cluster->merged_verts + 1; + vert_dest_map[v2] = v1; + vert_kill_len++; + } + } + + MEM_freeN(vert_clusters); + + for (uint i = 0; i < totvert; i++) { + if (i == vert_dest_map[i]) { + vert_dest_map[i] = OUT_OF_CONTEXT; + } + else { + uint v = i; + while ((v != vert_dest_map[v]) && (vert_dest_map[v] != OUT_OF_CONTEXT)) { + v = vert_dest_map[v]; + } + vert_dest_map[v] = v; + vert_dest_map[i] = v; + } + } + } if (v_mask) { MEM_freeN(v_mask); @@ -1940,6 +2021,7 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel) uiLayoutSetPropSep(layout, true); + uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE); uiItemR(layout, ptr, "merge_threshold", 0, IFACE_("Distance"), ICON_NONE); modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); @@ -1970,7 +2052,7 @@ ModifierTypeInfo modifierType_Weld = { /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c index 5f44848e2c3..d70a0c80c17 100644 --- a/source/blender/modifiers/intern/MOD_wireframe.c +++ b/source/blender/modifiers/intern/MOD_wireframe.c @@ -195,7 +195,7 @@ ModifierTypeInfo modifierType_Wireframe = { /* deformMatricesEM */ NULL, /* modifyMesh */ modifyMesh, /* modifyHair */ NULL, - /* modifyPointCloud */ NULL, + /* modifyGeometrySet */ NULL, /* modifyVolume */ NULL, /* initData */ initData, diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index a367f40dca7..60d4ee8f7c4 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -22,9 +22,9 @@ set(INC . composite function + geometry intern shader - geometry texture ../blenkernel ../blenlib @@ -73,6 +73,7 @@ set(SRC composite/nodes/node_composite_distanceMatte.c composite/nodes/node_composite_doubleEdgeMask.c composite/nodes/node_composite_ellipsemask.c + composite/nodes/node_composite_exposure.c composite/nodes/node_composite_filter.c composite/nodes/node_composite_flip.c composite/nodes/node_composite_gamma.c @@ -133,21 +134,28 @@ set(SRC function/nodes/node_fn_combine_strings.cc function/nodes/node_fn_float_compare.cc function/nodes/node_fn_group_instance_id.cc + function/nodes/node_fn_input_vector.cc function/nodes/node_fn_object_transforms.cc function/nodes/node_fn_random_float.cc function/nodes/node_fn_switch.cc function/node_function_util.cc + geometry/nodes/node_geo_attribute_color_ramp.cc + geometry/nodes/node_geo_attribute_compare.cc + geometry/nodes/node_geo_attribute_fill.cc geometry/nodes/node_geo_attribute_math.cc - geometry/nodes/node_geo_common.cc + geometry/nodes/node_geo_attribute_randomize.cc geometry/nodes/node_geo_boolean.cc + geometry/nodes/node_geo_common.cc geometry/nodes/node_geo_edge_split.cc geometry/nodes/node_geo_join_geometry.cc + geometry/nodes/node_geo_attribute_mix.cc geometry/nodes/node_geo_object_info.cc - geometry/nodes/node_geo_subdivision_surface.cc geometry/nodes/node_geo_point_distribute.cc + geometry/nodes/node_geo_point_distribute_poisson_disk.cc geometry/nodes/node_geo_point_instance.cc - geometry/nodes/node_geo_random_attribute.cc + geometry/nodes/node_geo_point_separate.cc + geometry/nodes/node_geo_subdivision_surface.cc geometry/nodes/node_geo_transform.cc geometry/nodes/node_geo_triangulate.cc geometry/node_geometry_exec.cc @@ -295,12 +303,12 @@ set(SRC NOD_composite.h NOD_derived_node_tree.hh NOD_function.h + NOD_geometry.h + NOD_math_functions.hh NOD_node_tree_dependencies.hh NOD_node_tree_multi_function.hh NOD_node_tree_ref.hh NOD_shader.h - NOD_geometry.h - NOD_math_functions.hh NOD_socket.h NOD_static_types.h NOD_texture.h @@ -311,9 +319,9 @@ set(SRC ) set(LIB + bf_bmesh bf_functions bf_intern_sky - bf_bmesh ) if(WITH_PYTHON) diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h index 99bcb849ebd..6ad02986010 100644 --- a/source/blender/nodes/NOD_composite.h +++ b/source/blender/nodes/NOD_composite.h @@ -56,6 +56,7 @@ void register_node_type_cmp_mix_rgb(void); void register_node_type_cmp_hue_sat(void); void register_node_type_cmp_brightcontrast(void); void register_node_type_cmp_gamma(void); +void register_node_type_cmp_exposure(void); void register_node_type_cmp_invert(void); void register_node_type_cmp_alphaover(void); void register_node_type_cmp_zcombine(void); diff --git a/source/blender/nodes/NOD_function.h b/source/blender/nodes/NOD_function.h index 58a968151ac..75dd8f89bc8 100644 --- a/source/blender/nodes/NOD_function.h +++ b/source/blender/nodes/NOD_function.h @@ -27,6 +27,7 @@ void register_node_type_fn_group_instance_id(void); void register_node_type_fn_combine_strings(void); void register_node_type_fn_object_transforms(void); void register_node_type_fn_random_float(void); +void register_node_type_fn_input_vector(void); #ifdef __cplusplus } diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h index 0532547375f..19a7acf2299 100644 --- a/source/blender/nodes/NOD_geometry.h +++ b/source/blender/nodes/NOD_geometry.h @@ -26,6 +26,7 @@ void register_node_tree_type_geo(void); void register_node_type_geo_group(void); +void register_node_type_geo_attribute_fill(void); void register_node_type_geo_boolean(void); void register_node_type_geo_edge_split(void); void register_node_type_geo_transform(void); @@ -34,9 +35,13 @@ void register_node_type_geo_triangulate(void); void register_node_type_geo_point_distribute(void); void register_node_type_geo_point_instance(void); void register_node_type_geo_object_info(void); -void register_node_type_geo_random_attribute(void); +void register_node_type_geo_attribute_randomize(void); void register_node_type_geo_attribute_math(void); void register_node_type_geo_join_geometry(void); +void register_node_type_geo_point_separate(void); +void register_node_type_geo_attribute_compare(void); +void register_node_type_geo_attribute_mix(void); +void register_node_type_geo_attribute_color_ramp(void); #ifdef __cplusplus } diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh index fde576d7429..f278d6b4107 100644 --- a/source/blender/nodes/NOD_geometry_exec.hh +++ b/source/blender/nodes/NOD_geometry_exec.hh @@ -26,12 +26,16 @@ namespace blender::nodes { +using bke::BooleanReadAttribute; +using bke::BooleanWriteAttribute; using bke::Color4fReadAttribute; using bke::Color4fWriteAttribute; using bke::Float3ReadAttribute; using bke::Float3WriteAttribute; using bke::FloatReadAttribute; using bke::FloatWriteAttribute; +using bke::Int32ReadAttribute; +using bke::Int32WriteAttribute; using bke::PersistentDataHandleMap; using bke::PersistentObjectHandle; using bke::ReadAttribute; @@ -40,6 +44,7 @@ using bke::WriteAttribute; using bke::WriteAttributePtr; using fn::CPPType; using fn::GMutablePointer; +using fn::GPointer; using fn::GValueMap; class GeoNodeExecParams { @@ -119,6 +124,16 @@ class GeoNodeExecParams { output_values_.add_new_by_move(identifier, value); } + void set_output_by_copy(StringRef identifier, GPointer value) + { +#ifdef DEBUG + BLI_assert(value.type() != nullptr); + BLI_assert(value.get() != nullptr); + this->check_set_output(identifier, *value.type()); +#endif + output_values_.add_new_by_copy(identifier, value); + } + /** * Store the output value for the given socket identifier. */ @@ -148,10 +163,41 @@ class GeoNodeExecParams { return self_object_; } + /** + * Creates a read-only attribute based on node inputs. The method automatically detects which + * input with the given name is available. + */ + ReadAttributePtr get_input_attribute(const StringRef name, + const GeometryComponent &component, + const AttributeDomain domain, + const CustomDataType type, + const void *default_value) const; + + template<typename T> + bke::TypedReadAttribute<T> get_input_attribute(const StringRef name, + const GeometryComponent &component, + const AttributeDomain domain, + const T &default_value) const + { + const CustomDataType type = bke::cpp_type_to_custom_data_type(CPPType::get<T>()); + return this->get_input_attribute(name, component, domain, type, &default_value); + } + + /** + * Get the type of an input property or the associated constant socket types with the + * same names. Fall back to the default value if no attribute exists with the name. + */ + CustomDataType get_input_attribute_data_type(const StringRef name, + const GeometryComponent &component, + const CustomDataType default_type) const; + private: /* Utilities for detecting common errors at when using this class. */ void check_extract_input(StringRef identifier, const CPPType *requested_type = nullptr) const; void check_set_output(StringRef identifier, const CPPType &value_type) const; + + /* Find the active socket socket with the input name (not the identifier). */ + const bNodeSocket *find_available_socket(const StringRef name) const; }; } // namespace blender::nodes diff --git a/source/blender/nodes/NOD_math_functions.hh b/source/blender/nodes/NOD_math_functions.hh index 70e4174a844..cc750f9595a 100644 --- a/source/blender/nodes/NOD_math_functions.hh +++ b/source/blender/nodes/NOD_math_functions.hh @@ -36,6 +36,7 @@ struct FloatMathOperationInfo { }; const FloatMathOperationInfo *get_float_math_operation_info(const int operation); +const FloatMathOperationInfo *get_float_compare_operation_info(const int operation); /** * This calls the `callback` with two arguments: @@ -197,4 +198,37 @@ inline bool try_dispatch_float_math_fl_fl_fl_to_fl(const int operation, Callback return false; } +/** + * This is similar to try_dispatch_float_math_fl_to_fl, just with a different callback signature. + */ +template<typename Callback> +inline bool try_dispatch_float_math_fl_fl_to_bool(const FloatCompareOperation operation, + Callback &&callback) +{ + const FloatMathOperationInfo *info = get_float_compare_operation_info(operation); + if (info == nullptr) { + return false; + } + + /* This is just an utility function to keep the individual cases smaller. */ + auto dispatch = [&](auto math_function) -> bool { + callback(math_function, *info); + return true; + }; + + switch (operation) { + case NODE_FLOAT_COMPARE_LESS_THAN: + return dispatch([](float a, float b) { return a < b; }); + case NODE_FLOAT_COMPARE_LESS_EQUAL: + return dispatch([](float a, float b) { return a <= b; }); + case NODE_FLOAT_COMPARE_GREATER_THAN: + return dispatch([](float a, float b) { return a > b; }); + case NODE_FLOAT_COMPARE_GREATER_EQUAL: + return dispatch([](float a, float b) { return a >= b; }); + default: + return false; + } + return false; +} + } // namespace blender::nodes diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 09e0908140c..5156bac0e73 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -222,6 +222,7 @@ DefNode(CompositorNode, CMP_NODE_CORNERPIN, 0, "CORNER DefNode(CompositorNode, CMP_NODE_SUNBEAMS, def_cmp_sunbeams, "SUNBEAMS", SunBeams, "Sun Beams", "" ) DefNode(CompositorNode, CMP_NODE_CRYPTOMATTE, def_cmp_cryptomatte, "CRYPTOMATTE", Cryptomatte, "Cryptomatte", "" ) DefNode(CompositorNode, CMP_NODE_DENOISE, def_cmp_denoise, "DENOISE", Denoise, "Denoise", "" ) +DefNode(CompositorNode, CMP_NODE_EXPOSURE, 0, "EXPOSURE", Exposure, "Exposure", "" ) DefNode(TextureNode, TEX_NODE_OUTPUT, def_tex_output, "OUTPUT", Output, "Output", "" ) DefNode(TextureNode, TEX_NODE_CHECKER, 0, "CHECKER", Checker, "Checker", "" ) @@ -265,18 +266,24 @@ DefNode(FunctionNode, FN_NODE_GROUP_INSTANCE_ID, 0, "GROUP_INSTANCE_ DefNode(FunctionNode, FN_NODE_COMBINE_STRINGS, 0, "COMBINE_STRINGS", CombineStrings, "Combine Strings", "") DefNode(FunctionNode, FN_NODE_OBJECT_TRANSFORMS, 0, "OBJECT_TRANSFORMS", ObjectTransforms, "Object Transforms", "") DefNode(FunctionNode, FN_NODE_RANDOM_FLOAT, 0, "RANDOM_FLOAT", RandomFloat, "Random Float", "") +DefNode(FunctionNode, FN_NODE_INPUT_VECTOR, def_fn_input_vector, "INPUT_VECTOR", InputVector, "Vector", "") DefNode(GeometryNode, GEO_NODE_TRIANGULATE, def_geo_triangulate, "TRIANGULATE", Triangulate, "Triangulate", "") DefNode(GeometryNode, GEO_NODE_EDGE_SPLIT, 0, "EDGE_SPLIT", EdgeSplit, "Edge Split", "") DefNode(GeometryNode, GEO_NODE_TRANSFORM, 0, "TRANSFORM", Transform, "Transform", "") DefNode(GeometryNode, GEO_NODE_SUBDIVISION_SURFACE, 0, "SUBDIVISION_SURFACE", SubdivisionSurface, "Subdivision Surface", "") DefNode(GeometryNode, GEO_NODE_BOOLEAN, def_geo_boolean, "BOOLEAN", Boolean, "Boolean", "") -DefNode(GeometryNode, GEO_NODE_POINT_DISTRIBUTE, 0, "POINT_DISTRIBUTE", PointDistribute, "Point Distribute", "") -DefNode(GeometryNode, GEO_NODE_POINT_INSTANCE, 0, "POINT_INSTANCE", PointInstance, "Point Instance", "") +DefNode(GeometryNode, GEO_NODE_POINT_DISTRIBUTE, def_geo_point_distribute, "POINT_DISTRIBUTE", PointDistribute, "Point Distribute", "") +DefNode(GeometryNode, GEO_NODE_POINT_INSTANCE, def_geo_point_instance, "POINT_INSTANCE", PointInstance, "Point Instance", "") DefNode(GeometryNode, GEO_NODE_OBJECT_INFO, 0, "OBJECT_INFO", ObjectInfo, "Object Info", "") -DefNode(GeometryNode, GEO_NODE_RANDOM_ATTRIBUTE, def_geo_random_attribute, "RANDOM_ATTRIBUTE", RandomAttribute, "Random Attribute", "") +DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_RANDOMIZE, def_geo_attribute_randomize, "ATTRIBUTE_RANDOMIZE", AttributeRandomize, "Attribute Randomize", "") DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_MATH, def_geo_attribute_math, "ATTRIBUTE_MATH", AttributeMath, "Attribute Math", "") DefNode(GeometryNode, GEO_NODE_JOIN_GEOMETRY, 0, "JOIN_GEOMETRY", JoinGeometry, "Join Geometry", "") +DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_FILL, def_geo_attribute_fill, "ATTRIBUTE_FILL", AttributeFill, "Attribute Fill", "") +DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_MIX, def_geo_attribute_mix, "ATTRIBUTE_MIX", AttributeMix, "Attribute Mix", "") +DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_COLOR_RAMP, def_geo_attribute_color_ramp, "ATTRIBUTE_COLOR_RAMP", AttributeColorRamp, "Attribute Color Ramp", "") +DefNode(GeometryNode, GEO_NODE_POINT_SEPARATE, 0, "POINT_SEPARATE", PointSeparate, "Point Separate", "") +DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_COMPARE, def_geo_attribute_attribute_compare, "ATTRIBUTE_COMPARE", AttributeCompare, "Attribute Compare", "") /* undefine macros */ #undef DefNode diff --git a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c index c8d2d993e75..f5308fe2671 100644 --- a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c +++ b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c @@ -27,172 +27,36 @@ #include "BLI_utildefines.h" #include "node_composite_util.h" -/* this is taken from the cryptomatte specification 1.0 */ - -BLI_INLINE float hash_to_float(uint32_t hash) +static CryptomatteEntry *cryptomatte_find(NodeCryptomatte *n, float encoded_hash) { - uint32_t mantissa = hash & ((1 << 23) - 1); - uint32_t exponent = (hash >> 23) & ((1 << 8) - 1); - exponent = MAX2(exponent, (uint32_t)1); - exponent = MIN2(exponent, (uint32_t)254); - exponent = exponent << 23; - uint32_t sign = (hash >> 31); - sign = sign << 31; - uint32_t float_bits = sign | exponent | mantissa; - float f; - /* Bit casting relies on equal size for both types. */ - BLI_STATIC_ASSERT(sizeof(float) == sizeof(uint32_t), "float and uint32_t are not the same size") - memcpy(&f, &float_bits, sizeof(float)); - return f; + LISTBASE_FOREACH (CryptomatteEntry *, entry, &n->entries) { + if (entry->encoded_hash == encoded_hash) { + return entry; + } + } + return NULL; } static void cryptomatte_add(NodeCryptomatte *n, float f) { - /* Turn the number into a string. */ - char number[32]; - BLI_snprintf(number, sizeof(number), "<%.9g>", f); - - /* Search if we already have the number. */ - if (n->matte_id && strlen(n->matte_id) != 0) { - size_t start = 0; - const size_t end = strlen(n->matte_id); - size_t token_len = 0; - while (start < end) { - /* Ignore leading whitespace. */ - while (start < end && n->matte_id[start] == ' ') { - start++; - } - - /* Find the next separator. */ - char *token_end = strchr(n->matte_id + start, ','); - if (ELEM(token_end, NULL, n->matte_id + start)) { - token_end = n->matte_id + end; - } - /* Be aware that token_len still contains any trailing white space. */ - token_len = token_end - (n->matte_id + start); - - /* If this has a leading bracket, - * assume a raw floating point number and look for the closing bracket. */ - if (n->matte_id[start] == '<') { - if (strncmp(n->matte_id + start, number, strlen(number)) == 0) { - /* This number is already there, so continue. */ - return; - } - } - else { - /* Remove trailing white space */ - size_t name_len = token_len; - while (n->matte_id[start + name_len] == ' ' && name_len > 0) { - name_len--; - } - /* Calculate the hash of the token and compare. */ - uint32_t hash = BLI_hash_mm3((const unsigned char *)(n->matte_id + start), name_len, 0); - if (f == hash_to_float(hash)) { - return; - } - } - start += token_len + 1; - } - } - - DynStr *new_matte = BLI_dynstr_new(); - if (!new_matte) { + /* Check if entry already exist. */ + if (cryptomatte_find(n, f) != NULL) { return; } - - if (n->matte_id) { - BLI_dynstr_append(new_matte, n->matte_id); - MEM_freeN(n->matte_id); - } - - if (BLI_dynstr_get_len(new_matte) > 0) { - BLI_dynstr_append(new_matte, ","); - } - BLI_dynstr_append(new_matte, number); - n->matte_id = BLI_dynstr_get_cstring(new_matte); - BLI_dynstr_free(new_matte); + CryptomatteEntry *entry = MEM_callocN(sizeof(CryptomatteEntry), __func__); + entry->encoded_hash = f; + BLI_addtail(&n->entries, entry); } static void cryptomatte_remove(NodeCryptomatte *n, float f) { - if (n->matte_id == NULL || strlen(n->matte_id) == 0) { - /* Empty string, nothing to remove. */ + CryptomatteEntry *entry = cryptomatte_find(n, f); + if (entry == NULL) { return; } - /* This will be the new string without the removed key. */ - DynStr *new_matte = BLI_dynstr_new(); - if (!new_matte) { - return; - } - - /* Turn the number into a string. */ - static char number[32]; - BLI_snprintf(number, sizeof(number), "<%.9g>", f); - - /* Search if we already have the number. */ - size_t start = 0; - const size_t end = strlen(n->matte_id); - size_t token_len = 0; - bool is_first = true; - while (start < end) { - bool skip = false; - /* Ignore leading whitespace or commas. */ - while (start < end && ((n->matte_id[start] == ' ') || (n->matte_id[start] == ','))) { - start++; - } - - /* Find the next separator. */ - char *token_end = strchr(n->matte_id + start + 1, ','); - if (ELEM(token_end, NULL, n->matte_id + start)) { - token_end = n->matte_id + end; - } - /* Be aware that token_len still contains any trailing white space. */ - token_len = token_end - (n->matte_id + start); - - if (token_len == 1) { - skip = true; - } - /* If this has a leading bracket, - * assume a raw floating point number and look for the closing bracket. */ - else if (n->matte_id[start] == '<') { - if (strncmp(n->matte_id + start, number, strlen(number)) == 0) { - /* This number is already there, so skip it. */ - skip = true; - } - } - else { - /* Remove trailing white space */ - size_t name_len = token_len; - while (n->matte_id[start + name_len] == ' ' && name_len > 0) { - name_len--; - } - /* Calculate the hash of the token and compare. */ - uint32_t hash = BLI_hash_mm3((const unsigned char *)(n->matte_id + start), name_len, 0); - if (f == hash_to_float(hash)) { - skip = true; - } - } - if (!skip) { - if (is_first) { - is_first = false; - } - else { - BLI_dynstr_append(new_matte, ", "); - } - BLI_dynstr_nappend(new_matte, n->matte_id + start, token_len); - } - start += token_len + 1; - } - - if (n->matte_id) { - MEM_freeN(n->matte_id); - n->matte_id = NULL; - } - if (BLI_dynstr_get_len(new_matte) > 0) { - n->matte_id = BLI_dynstr_get_cstring(new_matte); - } - BLI_dynstr_free(new_matte); + BLI_remlink(&n->entries, entry); + MEM_freeN(entry); } static bNodeSocketTemplate outputs[] = { @@ -265,10 +129,7 @@ static void node_free_cryptomatte(bNode *node) NodeCryptomatte *nc = node->storage; if (nc) { - if (nc->matte_id) { - MEM_freeN(nc->matte_id); - } - + BLI_freelistN(&nc->entries); MEM_freeN(nc); } } @@ -280,10 +141,7 @@ static void node_copy_cryptomatte(bNodeTree *UNUSED(dest_ntree), NodeCryptomatte *src_nc = src_node->storage; NodeCryptomatte *dest_nc = MEM_dupallocN(src_nc); - if (src_nc->matte_id) { - dest_nc->matte_id = MEM_dupallocN(src_nc->matte_id); - } - + BLI_duplicatelist(&dest_nc->entries, &src_nc->entries); dest_node->storage = dest_nc; } diff --git a/source/blender/nodes/composite/nodes/node_composite_exposure.c b/source/blender/nodes/composite/nodes/node_composite_exposure.c new file mode 100644 index 00000000000..bd27e4a3d76 --- /dev/null +++ b/source/blender/nodes/composite/nodes/node_composite_exposure.c @@ -0,0 +1,46 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup cmpnodes + */ + +#include "node_composite_util.h" + +/* **************** Exposure ******************** */ + +static bNodeSocketTemplate cmp_node_exposure_in[] = { + {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, + {SOCK_FLOAT, N_("Exposure"), 0.0f, 0.0f, 0.0f, 0.0f, -10.0f, 10.0f, PROP_NONE}, + {-1, ""}, +}; +static bNodeSocketTemplate cmp_node_exposure_out[] = { + {SOCK_RGBA, N_("Image")}, + {-1, ""}, +}; + +void register_node_type_cmp_exposure(void) +{ + static bNodeType ntype; + + cmp_node_type_base(&ntype, CMP_NODE_EXPOSURE, "Exposure", NODE_CLASS_OP_COLOR, 0); + node_type_socket_templates(&ntype, cmp_node_exposure_in, cmp_node_exposure_out); + + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/function/nodes/node_fn_input_vector.cc b/source/blender/nodes/function/nodes/node_fn_input_vector.cc new file mode 100644 index 00000000000..c2707f6307a --- /dev/null +++ b/source/blender/nodes/function/nodes/node_fn_input_vector.cc @@ -0,0 +1,55 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "node_function_util.hh" + +#include "BLI_hash.h" + +static bNodeSocketTemplate fn_node_input_vector_out[] = { + {SOCK_VECTOR, N_("Vector")}, + {-1, ""}, +}; + +static void fn_node_vector_input_expand_in_mf_network( + blender::nodes::NodeMFNetworkBuilder &builder) +{ + bNode &bnode = builder.bnode(); + NodeInputVector *node_storage = static_cast<NodeInputVector *>(bnode.storage); + blender::float3 vector(node_storage->vector); + + builder.construct_and_set_matching_fn<blender::fn::CustomMF_Constant<blender::float3>>(vector); +} + +static void fn_node_input_vector_init(bNodeTree *UNUSED(ntree), bNode *node) +{ + NodeInputVector *data = (NodeInputVector *)MEM_callocN(sizeof(NodeInputVector), + "input vector node"); + node->storage = data; +} + +void register_node_type_fn_input_vector() +{ + static bNodeType ntype; + + fn_node_type_base(&ntype, FN_NODE_INPUT_VECTOR, "Vector", 0, 0); + node_type_socket_templates(&ntype, nullptr, fn_node_input_vector_out); + node_type_init(&ntype, fn_node_input_vector_init); + node_type_storage( + &ntype, "NodeInputVector", node_free_standard_storage, node_copy_standard_storage); + ntype.expand_in_mf_network = fn_node_vector_input_expand_in_mf_network; + + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/node_geometry_util.cc b/source/blender/nodes/geometry/node_geometry_util.cc index 41bdb1cfff0..bcebaa6a37b 100644 --- a/source/blender/nodes/geometry/node_geometry_util.cc +++ b/source/blender/nodes/geometry/node_geometry_util.cc @@ -17,6 +17,69 @@ #include "node_geometry_util.hh" #include "node_util.h" +namespace blender::nodes { + +void update_attribute_input_socket_availabilities(bNode &node, + const StringRef name, + const GeometryNodeAttributeInputMode mode) +{ + const GeometryNodeAttributeInputMode mode_ = (GeometryNodeAttributeInputMode)mode; + LISTBASE_FOREACH (bNodeSocket *, socket, &node.inputs) { + if (name == socket->name) { + const bool is_available = + ((socket->type == SOCK_STRING && mode_ == GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE) || + (socket->type == SOCK_FLOAT && mode_ == GEO_NODE_ATTRIBUTE_INPUT_FLOAT) || + (socket->type == SOCK_VECTOR && mode_ == GEO_NODE_ATTRIBUTE_INPUT_VECTOR) || + (socket->type == SOCK_RGBA && mode_ == GEO_NODE_ATTRIBUTE_INPUT_COLOR)); + nodeSetSocketAvailability(socket, is_available); + } + } +} + +static int attribute_data_type_complexity(const CustomDataType data_type) +{ + switch (data_type) { + case CD_PROP_BOOL: + return 0; + case CD_PROP_INT32: + return 1; + case CD_PROP_FLOAT: + return 2; + case CD_PROP_FLOAT3: + return 4; + case CD_PROP_COLOR: + return 5; +#if 0 /* Attribute types are not supported yet. */ + case CD_MLOOPCOL: + return 3; + case CD_PROP_STRING: + return 6; +#endif + default: + /* Only accept "generic" custom data types used by the attribute system. */ + BLI_assert(false); + return 0; + } +} + +CustomDataType attribute_domain_highest_complexity(Span<CustomDataType> data_types) +{ + int highest_complexity = INT_MIN; + CustomDataType most_complex_type = CD_PROP_COLOR; + + for (const CustomDataType data_type : data_types) { + const int complexity = attribute_data_type_complexity(data_type); + if (complexity > highest_complexity) { + highest_complexity = complexity; + most_complex_type = data_type; + } + } + + return most_complex_type; +} + +} // namespace blender::nodes + bool geo_node_poll_default(bNodeType *UNUSED(ntype), bNodeTree *ntree) { return STREQ(ntree->idname, "GeometryNodeTree"); diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh index bb26763642b..7c12611a898 100644 --- a/source/blender/nodes/geometry/node_geometry_util.hh +++ b/source/blender/nodes/geometry/node_geometry_util.hh @@ -37,3 +37,20 @@ void geo_node_type_base( struct bNodeType *ntype, int type, const char *name, short nclass, short flag); bool geo_node_poll_default(struct bNodeType *ntype, struct bNodeTree *ntree); + +namespace blender::nodes { +void update_attribute_input_socket_availabilities(bNode &node, + const StringRef name, + const GeometryNodeAttributeInputMode mode); + +CustomDataType attribute_domain_highest_complexity(Span<CustomDataType>); + +void poisson_disk_point_elimination(Vector<float3> const *input_points, + Vector<float3> *output_points, + float maximum_distance, + float3 boundbox); + +Array<uint32_t> get_geometry_element_ids_as_uints(const GeometryComponent &component, + const AttributeDomain domain); + +} // namespace blender::nodes diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc new file mode 100644 index 00000000000..3f7023ba88f --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc @@ -0,0 +1,107 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "node_geometry_util.hh" + +#include "BKE_colorband.h" + +static bNodeSocketTemplate geo_node_attribute_color_ramp_in[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {SOCK_STRING, N_("Attribute")}, + {SOCK_STRING, N_("Result")}, + {-1, ""}, +}; + +static bNodeSocketTemplate geo_node_attribute_color_ramp_out[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {-1, ""}, +}; + +namespace blender::nodes { + +static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryComponent &component) +{ + const bNode &bnode = params.node(); + NodeAttributeColorRamp *node_storage = (NodeAttributeColorRamp *)bnode.storage; + + const std::string result_name = params.get_input<std::string>("Result"); + /* Once we support more domains at the user level, we have to decide how the result domain is + * choosen. */ + const AttributeDomain result_domain = ATTR_DOMAIN_POINT; + const CustomDataType result_type = CD_PROP_COLOR; + + WriteAttributePtr attribute_result = component.attribute_try_ensure_for_write( + result_name, result_domain, result_type); + if (!attribute_result) { + return; + } + + Color4fWriteAttribute attribute_out = std::move(attribute_result); + + const std::string input_name = params.get_input<std::string>("Attribute"); + FloatReadAttribute attribute_in = component.attribute_get_for_read<float>( + input_name, result_domain, 0.0f); + + Span<float> data_in = attribute_in.get_span(); + MutableSpan<Color4f> data_out = attribute_out.get_span(); + + ColorBand *color_ramp = &node_storage->color_ramp; + for (const int i : data_in.index_range()) { + BKE_colorband_evaluate(color_ramp, data_in[i], data_out[i]); + } + + attribute_out.apply_span(); +} + +static void geo_node_attribute_color_ramp_exec(GeoNodeExecParams params) +{ + GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); + + if (geometry_set.has<MeshComponent>()) { + execute_on_component(params, geometry_set.get_component_for_write<MeshComponent>()); + } + if (geometry_set.has<PointCloudComponent>()) { + execute_on_component(params, geometry_set.get_component_for_write<PointCloudComponent>()); + } + + params.set_output("Geometry", std::move(geometry_set)); +} + +static void geo_node_attribute_color_ramp_init(bNodeTree *UNUSED(ntree), bNode *node) +{ + NodeAttributeColorRamp *node_storage = (NodeAttributeColorRamp *)MEM_callocN( + sizeof(NodeAttributeColorRamp), __func__); + BKE_colorband_init(&node_storage->color_ramp, true); + node->storage = node_storage; +} + +} // namespace blender::nodes + +void register_node_type_geo_attribute_color_ramp() +{ + static bNodeType ntype; + + geo_node_type_base( + &ntype, GEO_NODE_ATTRIBUTE_COLOR_RAMP, "Attribute Color Ramp", NODE_CLASS_ATTRIBUTE, 0); + node_type_socket_templates( + &ntype, geo_node_attribute_color_ramp_in, geo_node_attribute_color_ramp_out); + node_type_storage( + &ntype, "NodeAttributeColorRamp", node_free_standard_storage, node_copy_standard_storage); + node_type_init(&ntype, blender::nodes::geo_node_attribute_color_ramp_init); + node_type_size_preset(&ntype, NODE_SIZE_LARGE); + ntype.geometry_node_execute = blender::nodes::geo_node_attribute_color_ramp_exec; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc new file mode 100644 index 00000000000..a3d5abfb3f2 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc @@ -0,0 +1,362 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "node_geometry_util.hh" + +#include "BKE_attribute.h" +#include "BKE_attribute_access.hh" + +#include "BLI_array.hh" +#include "BLI_math_base_safe.h" +#include "BLI_rand.hh" + +#include "DNA_mesh_types.h" +#include "DNA_pointcloud_types.h" + +#include "NOD_math_functions.hh" + +static bNodeSocketTemplate geo_node_attribute_compare_in[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {SOCK_STRING, N_("A")}, + {SOCK_FLOAT, N_("A"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX}, + {SOCK_VECTOR, N_("A"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX}, + {SOCK_RGBA, N_("A"), 0.5, 0.5, 0.5, 1.0}, + {SOCK_STRING, N_("B")}, + {SOCK_FLOAT, N_("B"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX}, + {SOCK_VECTOR, N_("B"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX}, + {SOCK_RGBA, N_("B"), 0.5, 0.5, 0.5, 1.0}, + {SOCK_FLOAT, N_("Threshold"), 0.01f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX}, + {SOCK_STRING, N_("Result")}, + {-1, ""}, +}; + +static bNodeSocketTemplate geo_node_attribute_compare_out[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {-1, ""}, +}; + +static void geo_node_attribute_compare_init(bNodeTree *UNUSED(tree), bNode *node) +{ + NodeAttributeCompare *data = (NodeAttributeCompare *)MEM_callocN(sizeof(NodeAttributeCompare), + "attribute mix node"); + data->operation = NODE_FLOAT_COMPARE_GREATER_THAN; + data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE; + data->input_type_b = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE; + node->storage = data; +} + +static bool operation_tests_equality(const NodeAttributeCompare &node_storage) +{ + return ELEM(node_storage.operation, NODE_FLOAT_COMPARE_EQUAL, NODE_FLOAT_COMPARE_NOT_EQUAL); +} + +namespace blender::nodes { + +static void geo_node_attribute_compare_update(bNodeTree *UNUSED(ntree), bNode *node) +{ + NodeAttributeCompare *node_storage = (NodeAttributeCompare *)node->storage; + update_attribute_input_socket_availabilities( + *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a); + update_attribute_input_socket_availabilities( + *node, "B", (GeometryNodeAttributeInputMode)node_storage->input_type_b); + + bNodeSocket *socket_threshold = (bNodeSocket *)BLI_findlink(&node->inputs, 9); + nodeSetSocketAvailability(socket_threshold, operation_tests_equality(*node_storage)); +} + +static void do_math_operation(const FloatReadAttribute &input_a, + const FloatReadAttribute &input_b, + const FloatCompareOperation operation, + MutableSpan<bool> span_result) +{ + const int size = input_a.size(); + + Span<float> span_a = input_a.get_span(); + Span<float> span_b = input_b.get_span(); + + if (try_dispatch_float_math_fl_fl_to_bool( + operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) { + for (const int i : IndexRange(size)) { + const float a = span_a[i]; + const float b = span_b[i]; + const bool out = math_function(a, b); + span_result[i] = out; + } + })) { + return; + } + + /* The operation is not supported by this node currently. */ + BLI_assert(false); +} + +static void do_equal_operation(const FloatReadAttribute &input_a, + const FloatReadAttribute &input_b, + const float threshold, + MutableSpan<bool> span_result) +{ + const int size = input_a.size(); + for (const int i : IndexRange(size)) { + const float a = input_a[i]; + const float b = input_b[i]; + span_result[i] = compare_ff(a, b, threshold); + } +} + +static void do_equal_operation(const Float3ReadAttribute &input_a, + const Float3ReadAttribute &input_b, + const float threshold, + MutableSpan<bool> span_result) +{ + const float threshold_squared = pow2f(threshold); + const int size = input_a.size(); + for (const int i : IndexRange(size)) { + const float3 a = input_a[i]; + const float3 b = input_b[i]; + span_result[i] = len_squared_v3v3(a, b) < threshold_squared; + } +} + +static void do_equal_operation(const Color4fReadAttribute &input_a, + const Color4fReadAttribute &input_b, + const float threshold, + MutableSpan<bool> span_result) +{ + const float threshold_squared = pow2f(threshold); + const int size = input_a.size(); + for (const int i : IndexRange(size)) { + const Color4f a = input_a[i]; + const Color4f b = input_b[i]; + span_result[i] = len_squared_v4v4(a, b) < threshold_squared; + } +} + +static void do_equal_operation(const BooleanReadAttribute &input_a, + const BooleanReadAttribute &input_b, + const float UNUSED(threshold), + MutableSpan<bool> span_result) +{ + const int size = input_a.size(); + for (const int i : IndexRange(size)) { + const bool a = input_a[i]; + const bool b = input_b[i]; + span_result[i] = a == b; + } +} + +static void do_not_equal_operation(const FloatReadAttribute &input_a, + const FloatReadAttribute &input_b, + const float threshold, + MutableSpan<bool> span_result) +{ + const int size = input_a.size(); + for (const int i : IndexRange(size)) { + const float a = input_a[i]; + const float b = input_b[i]; + span_result[i] = !compare_ff(a, b, threshold); + } +} + +static void do_not_equal_operation(const Float3ReadAttribute &input_a, + const Float3ReadAttribute &input_b, + const float threshold, + MutableSpan<bool> span_result) +{ + const float threshold_squared = pow2f(threshold); + const int size = input_a.size(); + for (const int i : IndexRange(size)) { + const float3 a = input_a[i]; + const float3 b = input_b[i]; + span_result[i] = len_squared_v3v3(a, b) >= threshold_squared; + } +} + +static void do_not_equal_operation(const Color4fReadAttribute &input_a, + const Color4fReadAttribute &input_b, + const float threshold, + MutableSpan<bool> span_result) +{ + const float threshold_squared = pow2f(threshold); + const int size = input_a.size(); + for (const int i : IndexRange(size)) { + const Color4f a = input_a[i]; + const Color4f b = input_b[i]; + span_result[i] = len_squared_v4v4(a, b) >= threshold_squared; + } +} + +static void do_not_equal_operation(const BooleanReadAttribute &input_a, + const BooleanReadAttribute &input_b, + const float UNUSED(threshold), + MutableSpan<bool> span_result) +{ + const int size = input_a.size(); + for (const int i : IndexRange(size)) { + const bool a = input_a[i]; + const bool b = input_b[i]; + span_result[i] = a != b; + } +} + +static CustomDataType get_data_type(GeometryComponent &component, + const GeoNodeExecParams ¶ms, + const NodeAttributeCompare &node_storage) +{ + if (operation_tests_equality(node_storage)) { + CustomDataType data_type_a = params.get_input_attribute_data_type( + "A", component, CD_PROP_FLOAT); + CustomDataType data_type_b = params.get_input_attribute_data_type( + "B", component, CD_PROP_FLOAT); + + /* Convert the input attributes to the same data type for the equality tests. Use the higher + * complexity attribute type, otherwise information necessary to the comparison may be lost. */ + return attribute_domain_highest_complexity({data_type_a, data_type_b}); + } + + /* Use float compare for every operation besides equality. */ + return CD_PROP_FLOAT; +} + +static void attribute_compare_calc(GeometryComponent &component, const GeoNodeExecParams ¶ms) +{ + const bNode &node = params.node(); + NodeAttributeCompare *node_storage = (NodeAttributeCompare *)node.storage; + const FloatCompareOperation operation = static_cast<FloatCompareOperation>( + node_storage->operation); + + /* The result type of this node is always float. */ + const CustomDataType result_type = CD_PROP_BOOL; + /* The result domain is always point for now. */ + const AttributeDomain result_domain = ATTR_DOMAIN_POINT; + + /* Get result attribute first, in case it has to overwrite one of the existing attributes. */ + const std::string result_name = params.get_input<std::string>("Result"); + WriteAttributePtr attribute_result = component.attribute_try_ensure_for_write( + result_name, result_domain, result_type); + if (!attribute_result) { + return; + } + + const CustomDataType input_data_type = get_data_type(component, params, *node_storage); + + ReadAttributePtr attribute_a = params.get_input_attribute( + "A", component, result_domain, input_data_type, nullptr); + ReadAttributePtr attribute_b = params.get_input_attribute( + "B", component, result_domain, input_data_type, nullptr); + + if (!attribute_a || !attribute_b) { + /* Attribute wasn't found. */ + return; + } + + BooleanWriteAttribute attribute_result_bool = std::move(attribute_result); + MutableSpan<bool> result_span = attribute_result_bool.get_span(); + + /* Use specific types for correct equality operations, but for other operations we use implicit + * conversions and float comparison. In other words, the comparison is not element-wise. */ + if (operation_tests_equality(*node_storage)) { + const float threshold = params.get_input<float>("Threshold"); + if (operation == NODE_FLOAT_COMPARE_EQUAL) { + if (input_data_type == CD_PROP_FLOAT) { + FloatReadAttribute attribute_a_float = std::move(attribute_a); + FloatReadAttribute attribute_b_float = std::move(attribute_b); + do_equal_operation( + std::move(attribute_a_float), std::move(attribute_b_float), threshold, result_span); + } + else if (input_data_type == CD_PROP_FLOAT3) { + Float3ReadAttribute attribute_a_float3 = std::move(attribute_a); + Float3ReadAttribute attribute_b_float3 = std::move(attribute_b); + do_equal_operation( + std::move(attribute_a_float3), std::move(attribute_b_float3), threshold, result_span); + } + else if (input_data_type == CD_PROP_COLOR) { + Color4fReadAttribute attribute_a_color = std::move(attribute_a); + Color4fReadAttribute attribute_b_color = std::move(attribute_b); + do_equal_operation( + std::move(attribute_a_color), std::move(attribute_b_color), threshold, result_span); + } + else if (input_data_type == CD_PROP_BOOL) { + BooleanReadAttribute attribute_a_bool = std::move(attribute_a); + BooleanReadAttribute attribute_b_bool = std::move(attribute_b); + do_equal_operation( + std::move(attribute_a_bool), std::move(attribute_b_bool), threshold, result_span); + } + } + else if (operation == NODE_FLOAT_COMPARE_NOT_EQUAL) { + if (input_data_type == CD_PROP_FLOAT) { + FloatReadAttribute attribute_a_float = std::move(attribute_a); + FloatReadAttribute attribute_b_float = std::move(attribute_b); + do_not_equal_operation( + std::move(attribute_a_float), std::move(attribute_b_float), threshold, result_span); + } + else if (input_data_type == CD_PROP_FLOAT3) { + Float3ReadAttribute attribute_a_float3 = std::move(attribute_a); + Float3ReadAttribute attribute_b_float3 = std::move(attribute_b); + do_not_equal_operation( + std::move(attribute_a_float3), std::move(attribute_b_float3), threshold, result_span); + } + else if (input_data_type == CD_PROP_COLOR) { + Color4fReadAttribute attribute_a_color = std::move(attribute_a); + Color4fReadAttribute attribute_b_color = std::move(attribute_b); + do_not_equal_operation( + std::move(attribute_a_color), std::move(attribute_b_color), threshold, result_span); + } + else if (input_data_type == CD_PROP_BOOL) { + BooleanReadAttribute attribute_a_bool = std::move(attribute_a); + BooleanReadAttribute attribute_b_bool = std::move(attribute_b); + do_not_equal_operation( + std::move(attribute_a_bool), std::move(attribute_b_bool), threshold, result_span); + } + } + } + else { + do_math_operation(std::move(attribute_a), std::move(attribute_b), operation, result_span); + } + + attribute_result_bool.apply_span(); +} + +static void geo_node_attribute_compare_exec(GeoNodeExecParams params) +{ + GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); + + if (geometry_set.has<MeshComponent>()) { + attribute_compare_calc(geometry_set.get_component_for_write<MeshComponent>(), params); + } + if (geometry_set.has<PointCloudComponent>()) { + attribute_compare_calc(geometry_set.get_component_for_write<PointCloudComponent>(), params); + } + + params.set_output("Geometry", geometry_set); +} + +} // namespace blender::nodes + +void register_node_type_geo_attribute_compare() +{ + static bNodeType ntype; + + geo_node_type_base( + &ntype, GEO_NODE_ATTRIBUTE_COMPARE, "Attribute Compare", NODE_CLASS_ATTRIBUTE, 0); + node_type_socket_templates( + &ntype, geo_node_attribute_compare_in, geo_node_attribute_compare_out); + ntype.geometry_node_execute = blender::nodes::geo_node_attribute_compare_exec; + node_type_update(&ntype, blender::nodes::geo_node_attribute_compare_update); + node_type_storage( + &ntype, "NodeAttributeCompare", node_free_standard_storage, node_copy_standard_storage); + node_type_init(&ntype, geo_node_attribute_compare_init); + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc new file mode 100644 index 00000000000..5cdbd18ecc8 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc @@ -0,0 +1,141 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "node_geometry_util.hh" + +#include "BLI_rand.hh" + +#include "DNA_mesh_types.h" +#include "DNA_pointcloud_types.h" + +static bNodeSocketTemplate geo_node_attribute_fill_in[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {SOCK_STRING, N_("Attribute")}, + {SOCK_VECTOR, N_("Value"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_FLOAT, N_("Value"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_RGBA, N_("Value"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_BOOLEAN, N_("Value"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {-1, ""}, +}; + +static bNodeSocketTemplate geo_node_attribute_fill_out[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {-1, ""}, +}; + +static void geo_node_attribute_fill_init(bNodeTree *UNUSED(tree), bNode *node) +{ + node->custom1 = CD_PROP_FLOAT; +} + +static void geo_node_attribute_fill_update(bNodeTree *UNUSED(ntree), bNode *node) +{ + bNodeSocket *socket_value_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 2); + bNodeSocket *socket_value_float = socket_value_vector->next; + bNodeSocket *socket_value_color4f = socket_value_float->next; + bNodeSocket *socket_value_boolean = socket_value_color4f->next; + + const CustomDataType data_type = static_cast<CustomDataType>(node->custom1); + + nodeSetSocketAvailability(socket_value_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(socket_value_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(socket_value_color4f, data_type == CD_PROP_COLOR); + nodeSetSocketAvailability(socket_value_boolean, data_type == CD_PROP_BOOL); +} + +namespace blender::nodes { + +static void fill_attribute(GeometryComponent &component, const GeoNodeExecParams ¶ms) +{ + const bNode &node = params.node(); + const CustomDataType data_type = static_cast<CustomDataType>(node.custom1); + const AttributeDomain domain = static_cast<AttributeDomain>(node.custom2); + const std::string attribute_name = params.get_input<std::string>("Attribute"); + if (attribute_name.empty()) { + return; + } + + WriteAttributePtr attribute = component.attribute_try_ensure_for_write( + attribute_name, domain, data_type); + if (!attribute) { + return; + } + + switch (data_type) { + case CD_PROP_FLOAT: { + FloatWriteAttribute float_attribute = std::move(attribute); + const float value = params.get_input<float>("Value_001"); + MutableSpan<float> attribute_span = float_attribute.get_span(); + attribute_span.fill(value); + float_attribute.apply_span(); + break; + } + case CD_PROP_FLOAT3: { + Float3WriteAttribute float3_attribute = std::move(attribute); + const float3 value = params.get_input<float3>("Value"); + MutableSpan<float3> attribute_span = float3_attribute.get_span(); + attribute_span.fill(value); + float3_attribute.apply_span(); + break; + } + case CD_PROP_COLOR: { + Color4fWriteAttribute color4f_attribute = std::move(attribute); + const Color4f value = params.get_input<Color4f>("Value_002"); + MutableSpan<Color4f> attribute_span = color4f_attribute.get_span(); + attribute_span.fill(value); + color4f_attribute.apply_span(); + break; + } + case CD_PROP_BOOL: { + BooleanWriteAttribute boolean_attribute = std::move(attribute); + const bool value = params.get_input<bool>("Value_003"); + MutableSpan<bool> attribute_span = boolean_attribute.get_span(); + attribute_span.fill(value); + boolean_attribute.apply_span(); + break; + } + default: + break; + } +} + +static void geo_node_attribute_fill_exec(GeoNodeExecParams params) +{ + GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); + + if (geometry_set.has<MeshComponent>()) { + fill_attribute(geometry_set.get_component_for_write<MeshComponent>(), params); + } + if (geometry_set.has<PointCloudComponent>()) { + fill_attribute(geometry_set.get_component_for_write<PointCloudComponent>(), params); + } + + params.set_output("Geometry", geometry_set); +} + +} // namespace blender::nodes + +void register_node_type_geo_attribute_fill() +{ + static bNodeType ntype; + + geo_node_type_base(&ntype, GEO_NODE_ATTRIBUTE_FILL, "Attribute Fill", NODE_CLASS_ATTRIBUTE, 0); + node_type_socket_templates(&ntype, geo_node_attribute_fill_in, geo_node_attribute_fill_out); + node_type_init(&ntype, geo_node_attribute_fill_init); + node_type_update(&ntype, geo_node_attribute_fill_update); + ntype.geometry_node_execute = blender::nodes::geo_node_attribute_fill_exec; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc index 455b2a79394..997b85c5e9d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc @@ -30,9 +30,9 @@ static bNodeSocketTemplate geo_node_attribute_math_in[] = { {SOCK_GEOMETRY, N_("Geometry")}, - {SOCK_STRING, N_("Attribute A")}, + {SOCK_STRING, N_("A")}, {SOCK_FLOAT, N_("A"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, - {SOCK_STRING, N_("Attribute B")}, + {SOCK_STRING, N_("B")}, {SOCK_FLOAT, N_("B"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, {SOCK_STRING, N_("Result")}, {-1, ""}, @@ -45,27 +45,27 @@ static bNodeSocketTemplate geo_node_attribute_math_out[] = { static void geo_node_attribute_math_init(bNodeTree *UNUSED(tree), bNode *node) { - node->custom1 = NODE_MATH_ADD; - node->custom2 = GEO_NODE_USE_ATTRIBUTE_A | GEO_NODE_USE_ATTRIBUTE_B; + NodeAttributeMath *data = (NodeAttributeMath *)MEM_callocN(sizeof(NodeAttributeMath), + "NodeAttributeMath"); + + data->operation = NODE_MATH_ADD; + data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE; + data->input_type_b = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE; + node->storage = data; } +namespace blender::nodes { + static void geo_node_attribute_math_update(bNodeTree *UNUSED(ntree), bNode *node) { - bNodeSocket *sock_attribute_a = (bNodeSocket *)BLI_findlink(&node->inputs, 1); - bNodeSocket *sock_float_a = sock_attribute_a->next; - bNodeSocket *sock_attribute_b = sock_float_a->next; - bNodeSocket *sock_float_b = sock_attribute_b->next; + NodeAttributeMath *node_storage = (NodeAttributeMath *)node->storage; - GeometryNodeUseAttributeFlag flag = static_cast<GeometryNodeUseAttributeFlag>(node->custom2); - - nodeSetSocketAvailability(sock_attribute_a, flag & GEO_NODE_USE_ATTRIBUTE_A); - nodeSetSocketAvailability(sock_attribute_b, flag & GEO_NODE_USE_ATTRIBUTE_B); - nodeSetSocketAvailability(sock_float_a, !(flag & GEO_NODE_USE_ATTRIBUTE_A)); - nodeSetSocketAvailability(sock_float_b, !(flag & GEO_NODE_USE_ATTRIBUTE_B)); + update_attribute_input_socket_availabilities( + *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a); + update_attribute_input_socket_availabilities( + *node, "B", (GeometryNodeAttributeInputMode)node_storage->input_type_b); } -namespace blender::nodes { - static void do_math_operation(const FloatReadAttribute &input_a, const FloatReadAttribute &input_b, FloatWriteAttribute result, @@ -97,7 +97,8 @@ static void do_math_operation(const FloatReadAttribute &input_a, static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecParams ¶ms) { const bNode &node = params.node(); - const int operation = node.custom1; + const NodeAttributeMath *node_storage = (const NodeAttributeMath *)node.storage; + const int operation = node_storage->operation; /* The result type of this node is always float. */ const CustomDataType result_type = CD_PROP_FLOAT; @@ -112,23 +113,10 @@ static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecP return; } - GeometryNodeUseAttributeFlag flag = static_cast<GeometryNodeUseAttributeFlag>(node.custom2); - - auto get_input_attribute = [&](GeometryNodeUseAttributeFlag use_flag, - StringRef attribute_socket_identifier, - StringRef value_socket_identifier) { - if (flag & use_flag) { - const std::string attribute_name = params.get_input<std::string>( - attribute_socket_identifier); - return component.attribute_try_get_for_read(attribute_name, result_domain, result_type); - } - const float value = params.get_input<float>(value_socket_identifier); - return component.attribute_get_constant_for_read(result_domain, result_type, &value); - }; - - ReadAttributePtr attribute_a = get_input_attribute(GEO_NODE_USE_ATTRIBUTE_A, "Attribute A", "A"); - ReadAttributePtr attribute_b = get_input_attribute(GEO_NODE_USE_ATTRIBUTE_B, "Attribute B", "B"); - + ReadAttributePtr attribute_a = params.get_input_attribute( + "A", component, result_domain, result_type, nullptr); + ReadAttributePtr attribute_b = params.get_input_attribute( + "B", component, result_domain, result_type, nullptr); if (!attribute_a || !attribute_b) { /* Attribute wasn't found. */ return; @@ -161,7 +149,9 @@ void register_node_type_geo_attribute_math() geo_node_type_base(&ntype, GEO_NODE_ATTRIBUTE_MATH, "Attribute Math", NODE_CLASS_ATTRIBUTE, 0); node_type_socket_templates(&ntype, geo_node_attribute_math_in, geo_node_attribute_math_out); ntype.geometry_node_execute = blender::nodes::geo_node_attribute_math_exec; - node_type_update(&ntype, geo_node_attribute_math_update); + node_type_update(&ntype, blender::nodes::geo_node_attribute_math_update); node_type_init(&ntype, geo_node_attribute_math_init); + node_type_storage( + &ntype, "NodeAttributeCompare", node_free_standard_storage, node_copy_standard_storage); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc new file mode 100644 index 00000000000..2f2558a2d53 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc @@ -0,0 +1,221 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "BKE_material.h" + +#include "DNA_material_types.h" + +#include "node_geometry_util.hh" + +static bNodeSocketTemplate geo_node_attribute_mix_in[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {SOCK_STRING, N_("Factor")}, + {SOCK_FLOAT, N_("Factor"), 0.5, 0.0, 0.0, 0.0, 0.0, 1.0, PROP_FACTOR}, + {SOCK_STRING, N_("A")}, + {SOCK_FLOAT, N_("A"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX}, + {SOCK_VECTOR, N_("A"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX}, + {SOCK_RGBA, N_("A"), 0.5, 0.5, 0.5, 1.0}, + {SOCK_STRING, N_("B")}, + {SOCK_FLOAT, N_("B"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX}, + {SOCK_VECTOR, N_("B"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX}, + {SOCK_RGBA, N_("B"), 0.5, 0.5, 0.5, 1.0}, + {SOCK_STRING, N_("Result")}, + {-1, ""}, +}; + +static bNodeSocketTemplate geo_node_mix_attribute_out[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {-1, ""}, +}; + +namespace blender::nodes { + +static void do_mix_operation_float(const int blend_mode, + const FloatReadAttribute &factors, + const FloatReadAttribute &inputs_a, + const FloatReadAttribute &inputs_b, + FloatWriteAttribute &results) +{ + const int size = results.size(); + for (const int i : IndexRange(size)) { + const float factor = factors[i]; + float3 a{inputs_a[i]}; + const float3 b{inputs_b[i]}; + ramp_blend(blend_mode, a, factor, b); + const float result = a.length(); + results.set(i, result); + } +} + +static void do_mix_operation_float3(const int blend_mode, + const FloatReadAttribute &factors, + const Float3ReadAttribute &inputs_a, + const Float3ReadAttribute &inputs_b, + Float3WriteAttribute &results) +{ + const int size = results.size(); + for (const int i : IndexRange(size)) { + const float factor = factors[i]; + float3 a = inputs_a[i]; + const float3 b = inputs_b[i]; + ramp_blend(blend_mode, a, factor, b); + results.set(i, a); + } +} + +static void do_mix_operation_color4f(const int blend_mode, + const FloatReadAttribute &factors, + const Color4fReadAttribute &inputs_a, + const Color4fReadAttribute &inputs_b, + Color4fWriteAttribute &results) +{ + const int size = results.size(); + for (const int i : IndexRange(size)) { + const float factor = factors[i]; + Color4f a = inputs_a[i]; + const Color4f b = inputs_b[i]; + ramp_blend(blend_mode, a, factor, b); + results.set(i, a); + } +} + +static void do_mix_operation(const CustomDataType result_type, + int blend_mode, + const FloatReadAttribute &attribute_factor, + ReadAttributePtr attribute_a, + ReadAttributePtr attribute_b, + WriteAttributePtr attribute_result) +{ + if (result_type == CD_PROP_FLOAT) { + FloatReadAttribute attribute_a_float = std::move(attribute_a); + FloatReadAttribute attribute_b_float = std::move(attribute_b); + FloatWriteAttribute attribute_result_float = std::move(attribute_result); + do_mix_operation_float(blend_mode, + attribute_factor, + attribute_a_float, + attribute_b_float, + attribute_result_float); + } + else if (result_type == CD_PROP_FLOAT3) { + Float3ReadAttribute attribute_a_float3 = std::move(attribute_a); + Float3ReadAttribute attribute_b_float3 = std::move(attribute_b); + Float3WriteAttribute attribute_result_float3 = std::move(attribute_result); + do_mix_operation_float3(blend_mode, + attribute_factor, + attribute_a_float3, + attribute_b_float3, + attribute_result_float3); + } + else if (result_type == CD_PROP_COLOR) { + Color4fReadAttribute attribute_a_color4f = std::move(attribute_a); + Color4fReadAttribute attribute_b_color4f = std::move(attribute_b); + Color4fWriteAttribute attribute_result_color4f = std::move(attribute_result); + do_mix_operation_color4f(blend_mode, + attribute_factor, + attribute_a_color4f, + attribute_b_color4f, + attribute_result_color4f); + } +} + +static void attribute_mix_calc(GeometryComponent &component, const GeoNodeExecParams ¶ms) +{ + const bNode &node = params.node(); + const NodeAttributeMix *node_storage = (const NodeAttributeMix *)node.storage; + + CustomDataType result_type = CD_PROP_COLOR; + AttributeDomain result_domain = ATTR_DOMAIN_POINT; + + /* Use type and domain from the result attribute, if it exists already. */ + const std::string result_name = params.get_input<std::string>("Result"); + const ReadAttributePtr result_attribute_read = component.attribute_try_get_for_read(result_name); + if (result_attribute_read) { + result_type = result_attribute_read->custom_data_type(); + result_domain = result_attribute_read->domain(); + } + + WriteAttributePtr attribute_result = component.attribute_try_ensure_for_write( + result_name, result_domain, result_type); + if (!attribute_result) { + return; + } + + FloatReadAttribute attribute_factor = params.get_input_attribute<float>( + "Factor", component, result_domain, 0.5f); + ReadAttributePtr attribute_a = params.get_input_attribute( + "A", component, result_domain, result_type, nullptr); + ReadAttributePtr attribute_b = params.get_input_attribute( + "B", component, result_domain, result_type, nullptr); + + do_mix_operation(result_type, + node_storage->blend_type, + attribute_factor, + std::move(attribute_a), + std::move(attribute_b), + std::move(attribute_result)); +} + +static void geo_node_attribute_mix_exec(GeoNodeExecParams params) +{ + GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); + + if (geometry_set.has<MeshComponent>()) { + attribute_mix_calc(geometry_set.get_component_for_write<MeshComponent>(), params); + } + if (geometry_set.has<PointCloudComponent>()) { + attribute_mix_calc(geometry_set.get_component_for_write<PointCloudComponent>(), params); + } + + params.set_output("Geometry", geometry_set); +} + +static void geo_node_attribute_mix_init(bNodeTree *UNUSED(ntree), bNode *node) +{ + NodeAttributeMix *data = (NodeAttributeMix *)MEM_callocN(sizeof(NodeAttributeMix), + "attribute mix node"); + data->blend_type = MA_RAMP_BLEND; + data->input_type_factor = GEO_NODE_ATTRIBUTE_INPUT_FLOAT; + data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE; + data->input_type_b = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE; + node->storage = data; +} + +static void geo_node_attribute_mix_update(bNodeTree *UNUSED(ntree), bNode *node) +{ + NodeAttributeMix *node_storage = (NodeAttributeMix *)node->storage; + update_attribute_input_socket_availabilities( + *node, "Factor", (GeometryNodeAttributeInputMode)node_storage->input_type_factor); + update_attribute_input_socket_availabilities( + *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a); + update_attribute_input_socket_availabilities( + *node, "B", (GeometryNodeAttributeInputMode)node_storage->input_type_b); +} + +} // namespace blender::nodes + +void register_node_type_geo_attribute_mix() +{ + static bNodeType ntype; + + geo_node_type_base(&ntype, GEO_NODE_ATTRIBUTE_MIX, "Attribute Mix", NODE_CLASS_ATTRIBUTE, 0); + node_type_socket_templates(&ntype, geo_node_attribute_mix_in, geo_node_mix_attribute_out); + node_type_init(&ntype, blender::nodes::geo_node_attribute_mix_init); + node_type_update(&ntype, blender::nodes::geo_node_attribute_mix_update); + node_type_storage( + &ntype, "NodeAttributeMix", node_free_standard_storage, node_copy_standard_storage); + ntype.geometry_node_execute = blender::nodes::geo_node_attribute_mix_exec; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_random_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc index 5cacb96412c..b8b53a17ecc 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_random_attribute.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc @@ -16,12 +16,13 @@ #include "node_geometry_util.hh" +#include "BLI_hash.h" #include "BLI_rand.hh" #include "DNA_mesh_types.h" #include "DNA_pointcloud_types.h" -static bNodeSocketTemplate geo_node_random_attribute_in[] = { +static bNodeSocketTemplate geo_node_attribute_randomize_in[] = { {SOCK_GEOMETRY, N_("Geometry")}, {SOCK_STRING, N_("Attribute")}, {SOCK_VECTOR, N_("Min"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, @@ -32,17 +33,17 @@ static bNodeSocketTemplate geo_node_random_attribute_in[] = { {-1, ""}, }; -static bNodeSocketTemplate geo_node_random_attribute_out[] = { +static bNodeSocketTemplate geo_node_attribute_randomize_out[] = { {SOCK_GEOMETRY, N_("Geometry")}, {-1, ""}, }; -static void geo_node_random_attribute_init(bNodeTree *UNUSED(tree), bNode *node) +static void geo_node_attribute_randomize_init(bNodeTree *UNUSED(tree), bNode *node) { node->custom1 = CD_PROP_FLOAT; } -static void geo_node_random_attribute_update(bNodeTree *UNUSED(ntree), bNode *node) +static void geo_node_attribute_randomize_update(bNodeTree *UNUSED(ntree), bNode *node) { bNodeSocket *sock_min_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 2); bNodeSocket *sock_max_vector = sock_min_vector->next; @@ -59,38 +60,88 @@ static void geo_node_random_attribute_update(bNodeTree *UNUSED(ntree), bNode *no namespace blender::nodes { -static void randomize_attribute(FloatWriteAttribute &attribute, - float min, - float max, - RandomNumberGenerator &rng) +/** Rehash to combine the seed with the "id" hash and a mutator for each dimension. */ +static float noise_from_index_and_mutator(const int seed, const int hash, const int mutator) +{ + const int combined_hash = BLI_hash_int_3d(seed, hash, mutator); + return BLI_hash_int_01(combined_hash); +} + +/** Rehash to combine the seed with the "id" hash. */ +static float noise_from_index(const int seed, const int hash) +{ + const int combined_hash = BLI_hash_int_2d(seed, hash); + return BLI_hash_int_01(combined_hash); +} + +static void randomize_attribute(BooleanWriteAttribute &attribute, + Span<uint32_t> hashes, + const int seed) +{ + MutableSpan<bool> attribute_span = attribute.get_span(); + for (const int i : IndexRange(attribute.size())) { + const bool value = noise_from_index(seed, (int)hashes[i]) > 0.5f; + attribute_span[i] = value; + } + attribute.apply_span(); +} + +static void randomize_attribute( + FloatWriteAttribute &attribute, float min, float max, Span<uint32_t> hashes, const int seed) { MutableSpan<float> attribute_span = attribute.get_span(); for (const int i : IndexRange(attribute.size())) { - const float value = rng.get_float() * (max - min) + min; + const float value = noise_from_index(seed, (int)hashes[i]) * (max - min) + min; attribute_span[i] = value; } attribute.apply_span(); } -static void randomize_attribute(Float3WriteAttribute &attribute, - float3 min, - float3 max, - RandomNumberGenerator &rng) +static void randomize_attribute( + Float3WriteAttribute &attribute, float3 min, float3 max, Span<uint32_t> hashes, const int seed) { MutableSpan<float3> attribute_span = attribute.get_span(); for (const int i : IndexRange(attribute.size())) { - const float x = rng.get_float(); - const float y = rng.get_float(); - const float z = rng.get_float(); + const float x = noise_from_index_and_mutator(seed, (int)hashes[i], 47); + const float y = noise_from_index_and_mutator(seed, (int)hashes[i], 8); + const float z = noise_from_index_and_mutator(seed, (int)hashes[i], 64); const float3 value = float3(x, y, z) * (max - min) + min; attribute_span[i] = value; } attribute.apply_span(); } +Array<uint32_t> get_geometry_element_ids_as_uints(const GeometryComponent &component, + const AttributeDomain domain) +{ + const int domain_size = component.attribute_domain_size(domain); + + /* Hash the reserved name attribute "id" as a (hopefully) stable seed for each point. */ + ReadAttributePtr hash_attribute = component.attribute_try_get_for_read("id", domain); + Array<uint32_t> hashes(domain_size); + if (hash_attribute) { + BLI_assert(hashes.size() == hash_attribute->size()); + const CPPType &cpp_type = hash_attribute->cpp_type(); + fn::GSpan items = hash_attribute->get_span(); + for (const int i : hashes.index_range()) { + hashes[i] = cpp_type.hash(items[i]); + } + } + else { + /* If there is no "id" attribute for per-point variation, just create it here. */ + RandomNumberGenerator rng; + rng.seed(0); + for (const int i : hashes.index_range()) { + hashes[i] = rng.get_uint32(); + } + } + + return hashes; +} + static void randomize_attribute(GeometryComponent &component, const GeoNodeExecParams ¶ms, - RandomNumberGenerator &rng) + const int seed) { const bNode &node = params.node(); const CustomDataType data_type = static_cast<CustomDataType>(node.custom1); @@ -106,19 +157,26 @@ static void randomize_attribute(GeometryComponent &component, return; } + Array<uint32_t> hashes = get_geometry_element_ids_as_uints(component, domain); + switch (data_type) { case CD_PROP_FLOAT: { FloatWriteAttribute float_attribute = std::move(attribute); const float min_value = params.get_input<float>("Min_001"); const float max_value = params.get_input<float>("Max_001"); - randomize_attribute(float_attribute, min_value, max_value, rng); + randomize_attribute(float_attribute, min_value, max_value, hashes, seed); break; } case CD_PROP_FLOAT3: { Float3WriteAttribute float3_attribute = std::move(attribute); const float3 min_value = params.get_input<float3>("Min"); const float3 max_value = params.get_input<float3>("Max"); - randomize_attribute(float3_attribute, min_value, max_value, rng); + randomize_attribute(float3_attribute, min_value, max_value, hashes, seed); + break; + } + case CD_PROP_BOOL: { + BooleanWriteAttribute boolean_attribute = std::move(attribute); + randomize_attribute(boolean_attribute, hashes, seed); break; } default: @@ -132,14 +190,10 @@ static void geo_node_random_attribute_exec(GeoNodeExecParams params) const int seed = params.get_input<int>("Seed"); if (geometry_set.has<MeshComponent>()) { - RandomNumberGenerator rng; - rng.seed_random(seed); - randomize_attribute(geometry_set.get_component_for_write<MeshComponent>(), params, rng); + randomize_attribute(geometry_set.get_component_for_write<MeshComponent>(), params, seed); } if (geometry_set.has<PointCloudComponent>()) { - RandomNumberGenerator rng; - rng.seed_random(seed + 3245231); - randomize_attribute(geometry_set.get_component_for_write<PointCloudComponent>(), params, rng); + randomize_attribute(geometry_set.get_component_for_write<PointCloudComponent>(), params, seed); } params.set_output("Geometry", geometry_set); @@ -147,15 +201,16 @@ static void geo_node_random_attribute_exec(GeoNodeExecParams params) } // namespace blender::nodes -void register_node_type_geo_random_attribute() +void register_node_type_geo_attribute_randomize() { static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_RANDOM_ATTRIBUTE, "Random Attribute", NODE_CLASS_ATTRIBUTE, 0); - node_type_socket_templates(&ntype, geo_node_random_attribute_in, geo_node_random_attribute_out); - node_type_init(&ntype, geo_node_random_attribute_init); - node_type_update(&ntype, geo_node_random_attribute_update); + &ntype, GEO_NODE_ATTRIBUTE_RANDOMIZE, "Attribute Randomize", NODE_CLASS_ATTRIBUTE, 0); + node_type_socket_templates( + &ntype, geo_node_attribute_randomize_in, geo_node_attribute_randomize_out); + node_type_init(&ntype, geo_node_attribute_randomize_init); + node_type_update(&ntype, geo_node_attribute_randomize_update); ntype.geometry_node_execute = blender::nodes::geo_node_random_attribute_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc index dedc3213a1f..80ac45aed4e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc @@ -218,12 +218,12 @@ static void join_components(Span<const InstancesComponent *> src_components, Geo InstancesComponent &dst_component = result.get_component_for_write<InstancesComponent>(); for (const InstancesComponent *component : src_components) { const int size = component->instances_amount(); - Span<const Object *> objects = component->objects(); + Span<InstancedData> instanced_data = component->instanced_data(); Span<float3> positions = component->positions(); Span<float3> rotations = component->rotations(); Span<float3> scales = component->scales(); for (const int i : IndexRange(size)) { - dst_component.add_instance(objects[i], positions[i], rotations[i], scales[i]); + dst_component.add_instance(instanced_data[i], positions[i], rotations[i], scales[i]); } } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc index 2f5f7e264bc..1d3fbae5b2e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc @@ -24,6 +24,7 @@ #include "DNA_meshdata_types.h" #include "DNA_pointcloud_types.h" +#include "BKE_bvhutils.h" #include "BKE_deform.h" #include "BKE_mesh.h" #include "BKE_mesh_runtime.h" @@ -33,8 +34,10 @@ static bNodeSocketTemplate geo_node_point_distribute_in[] = { {SOCK_GEOMETRY, N_("Geometry")}, - {SOCK_FLOAT, N_("Density"), 10.0f, 0.0f, 0.0f, 0.0f, 0.0f, 100000.0f, PROP_NONE}, + {SOCK_FLOAT, N_("Distance Min"), 0.1f, 0.0f, 0.0f, 0.0f, 0.0f, 100000.0f, PROP_NONE}, + {SOCK_FLOAT, N_("Density Max"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 100000.0f, PROP_NONE}, {SOCK_STRING, N_("Density Attribute")}, + {SOCK_INT, N_("Seed"), 0, 0, 0, 0, -10000, 10000}, {-1, ""}, }; @@ -43,11 +46,20 @@ static bNodeSocketTemplate geo_node_point_distribute_out[] = { {-1, ""}, }; +static void node_point_distribute_update(bNodeTree *UNUSED(ntree), bNode *node) +{ + bNodeSocket *sock_min_dist = (bNodeSocket *)BLI_findlink(&node->inputs, 1); + + nodeSetSocketAvailability(sock_min_dist, ELEM(node->custom1, GEO_NODE_POINT_DISTRIBUTE_POISSON)); +} + namespace blender::nodes { -static Vector<float3> scatter_points_from_mesh(const Mesh *mesh, - const float density, - const FloatReadAttribute &density_factors) +static Vector<float3> random_scatter_points_from_mesh(const Mesh *mesh, + const float density, + const FloatReadAttribute &density_factors, + Vector<int> &r_ids, + const int seed) { /* This only updates a cache and can be considered to be logically const. */ const MLoopTri *looptris = BKE_mesh_runtime_looptri_ensure(const_cast<Mesh *>(mesh)); @@ -71,7 +83,7 @@ static Vector<float3> scatter_points_from_mesh(const Mesh *mesh, 3.0f; const float area = area_tri_v3(v0_pos, v1_pos, v2_pos); - const int looptri_seed = BLI_hash_int(looptri_index); + const int looptri_seed = BLI_hash_int(looptri_index + seed); RandomNumberGenerator looptri_rng(looptri_seed); const float points_amount_fl = area * density * looptri_density_factor; @@ -84,23 +96,178 @@ static Vector<float3> scatter_points_from_mesh(const Mesh *mesh, float3 point_pos; interp_v3_v3v3v3(point_pos, v0_pos, v1_pos, v2_pos, bary_coords); points.append(point_pos); + + /* Build a hash stable even when the mesh is deformed. */ + r_ids.append(((int)(bary_coords.hash()) + looptri_index)); } } return points; } +struct RayCastAll_Data { + void *bvhdata; + + BVHTree_RayCastCallback raycast_callback; + + /** The original coordinate the result point was projected from. */ + float2 raystart; + + const Mesh *mesh; + float base_weight; + FloatReadAttribute *density_factors; + Vector<float3> *projected_points; + Vector<int> *stable_ids; + float cur_point_weight; +}; + +static void project_2d_bvh_callback(void *userdata, + int index, + const BVHTreeRay *ray, + BVHTreeRayHit *hit) +{ + struct RayCastAll_Data *data = (RayCastAll_Data *)userdata; + data->raycast_callback(data->bvhdata, index, ray, hit); + if (hit->index != -1) { + /* This only updates a cache and can be considered to be logically const. */ + const MLoopTri *looptris = BKE_mesh_runtime_looptri_ensure(const_cast<Mesh *>(data->mesh)); + const MVert *mvert = data->mesh->mvert; + + const MLoopTri &looptri = looptris[index]; + const FloatReadAttribute &density_factors = data->density_factors[0]; + + const int v0_index = data->mesh->mloop[looptri.tri[0]].v; + const int v1_index = data->mesh->mloop[looptri.tri[1]].v; + const int v2_index = data->mesh->mloop[looptri.tri[2]].v; + + const float v0_density_factor = std::max(0.0f, density_factors[v0_index]); + const float v1_density_factor = std::max(0.0f, density_factors[v1_index]); + const float v2_density_factor = std::max(0.0f, density_factors[v2_index]); + + /* Calculate barycentric weights for hit point. */ + float3 weights; + interp_weights_tri_v3( + weights, mvert[v0_index].co, mvert[v1_index].co, mvert[v2_index].co, hit->co); + + float point_weight = weights[0] * v0_density_factor + weights[1] * v1_density_factor + + weights[2] * v2_density_factor; + + point_weight *= data->base_weight; + + if (point_weight >= FLT_EPSILON && data->cur_point_weight <= point_weight) { + data->projected_points->append(hit->co); + + /* Build a hash stable even when the mesh is deformed. */ + data->stable_ids->append((int)data->raystart.hash()); + } + } +} + +static Vector<float3> poisson_scatter_points_from_mesh(const Mesh *mesh, + const float density, + const float minimum_distance, + const FloatReadAttribute &density_factors, + Vector<int> &r_ids, + const int seed) +{ + Vector<float3> points; + + if (minimum_distance <= FLT_EPSILON || density <= FLT_EPSILON) { + return points; + } + + /* Scatter points randomly on the mesh with higher density (5-7) times higher than desired for + * good quality possion disk distributions. */ + int quality = 5; + const int output_points_target = 1000; + points.resize(output_points_target * quality); + + const float required_area = output_points_target * + (2.0f * sqrtf(3.0f) * minimum_distance * minimum_distance); + const float point_scale_multiplier = sqrtf(required_area); + + { + const int rnd_seed = BLI_hash_int(seed); + RandomNumberGenerator point_rng(rnd_seed); + + for (int i = 0; i < points.size(); i++) { + points[i].x = point_rng.get_float() * point_scale_multiplier; + points[i].y = point_rng.get_float() * point_scale_multiplier; + points[i].z = 0.0f; + } + } + + /* Eliminate the scattered points until we get a possion distribution. */ + Vector<float3> output_points(output_points_target); + + const float3 bounds_max = float3(point_scale_multiplier, point_scale_multiplier, 0); + poisson_disk_point_elimination(&points, &output_points, 2.0f * minimum_distance, bounds_max); + Vector<float3> final_points; + r_ids.reserve(output_points_target); + final_points.reserve(output_points_target); + + /* Check if we have any points we should remove from the final possion distribition. */ + BVHTreeFromMesh treedata; + BKE_bvhtree_from_mesh_get(&treedata, const_cast<Mesh *>(mesh), BVHTREE_FROM_LOOPTRI, 2); + + float3 bb_min, bb_max; + BLI_bvhtree_get_bounding_box(treedata.tree, bb_min, bb_max); + + struct RayCastAll_Data data; + data.bvhdata = &treedata; + data.raycast_callback = treedata.raycast_callback; + data.mesh = mesh; + data.projected_points = &final_points; + data.stable_ids = &r_ids; + data.density_factors = const_cast<FloatReadAttribute *>(&density_factors); + data.base_weight = std::min( + 1.0f, density / (output_points.size() / (point_scale_multiplier * point_scale_multiplier))); + + const float max_dist = bb_max[2] - bb_min[2] + 2.0f; + const float3 dir = float3(0, 0, -1); + float3 raystart; + raystart.z = bb_max[2] + 1.0f; + + float tile_start_x_coord = bb_min[0]; + int tile_repeat_x = ceilf((bb_max[0] - bb_min[0]) / point_scale_multiplier); + + float tile_start_y_coord = bb_min[1]; + int tile_repeat_y = ceilf((bb_max[1] - bb_min[1]) / point_scale_multiplier); + + for (int x = 0; x < tile_repeat_x; x++) { + float tile_curr_x_coord = x * point_scale_multiplier + tile_start_x_coord; + for (int y = 0; y < tile_repeat_y; y++) { + float tile_curr_y_coord = y * point_scale_multiplier + tile_start_y_coord; + for (int idx = 0; idx < output_points.size(); idx++) { + raystart.x = output_points[idx].x + tile_curr_x_coord; + raystart.y = output_points[idx].y + tile_curr_y_coord; + + data.cur_point_weight = (float)idx / (float)output_points.size(); + data.raystart = raystart; + + BLI_bvhtree_ray_cast_all( + treedata.tree, raystart, dir, 0.0f, max_dist, project_2d_bvh_callback, &data); + } + } + } + + return final_points; +} + static void geo_node_point_distribute_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); GeometrySet geometry_set_out; + GeometryNodePointDistributeMethod distribute_method = + static_cast<GeometryNodePointDistributeMethod>(params.node().custom1); + if (!geometry_set.has_mesh()) { params.set_output("Geometry", std::move(geometry_set_out)); return; } - const float density = params.extract_input<float>("Density"); + const float density = params.extract_input<float>("Density Max"); const std::string density_attribute = params.extract_input<std::string>("Density Attribute"); if (density <= 0.0f) { @@ -113,8 +280,21 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params) const FloatReadAttribute density_factors = mesh_component.attribute_get_for_read<float>( density_attribute, ATTR_DOMAIN_POINT, 1.0f); + const int seed = params.get_input<int>("Seed"); - Vector<float3> points = scatter_points_from_mesh(mesh_in, density, density_factors); + Vector<int> stable_ids; + Vector<float3> points; + switch (distribute_method) { + case GEO_NODE_POINT_DISTRIBUTE_RANDOM: + points = random_scatter_points_from_mesh( + mesh_in, density, density_factors, stable_ids, seed); + break; + case GEO_NODE_POINT_DISTRIBUTE_POISSON: + const float min_dist = params.extract_input<float>("Distance Min"); + points = poisson_scatter_points_from_mesh( + mesh_in, density, min_dist, density_factors, stable_ids, seed); + break; + } PointCloud *pointcloud = BKE_pointcloud_new_nomain(points.size()); memcpy(pointcloud->co, points.data(), sizeof(float3) * points.size()); @@ -123,7 +303,16 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params) pointcloud->radius[i] = 0.05f; } - geometry_set_out.replace_pointcloud(pointcloud); + PointCloudComponent &point_component = + geometry_set_out.get_component_for_write<PointCloudComponent>(); + point_component.replace(pointcloud); + + Int32WriteAttribute stable_id_attribute = point_component.attribute_try_ensure_for_write( + "id", ATTR_DOMAIN_POINT, CD_PROP_INT32); + MutableSpan<int> stable_ids_span = stable_id_attribute.get_span(); + stable_ids_span.copy_from(stable_ids); + stable_id_attribute.apply_span(); + params.set_output("Geometry", std::move(geometry_set_out)); } } // namespace blender::nodes @@ -135,6 +324,7 @@ void register_node_type_geo_point_distribute() geo_node_type_base( &ntype, GEO_NODE_POINT_DISTRIBUTE, "Point Distribute", NODE_CLASS_GEOMETRY, 0); node_type_socket_templates(&ntype, geo_node_point_distribute_in, geo_node_point_distribute_out); + node_type_update(&ntype, node_point_distribute_update); ntype.geometry_node_execute = blender::nodes::geo_node_point_distribute_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_distribute_poisson_disk.cc b/source/blender/nodes/geometry/nodes/node_geo_point_distribute_poisson_disk.cc new file mode 100644 index 00000000000..e53157cb5f8 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_point_distribute_poisson_disk.cc @@ -0,0 +1,281 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/* + * Based on Cem Yuksel. 2015. Sample Elimination for Generating Poisson Disk Sample + * ! Sets. Computer Graphics Forum 34, 2 (May 2015), 25-32. + * ! http://www.cemyuksel.com/research/sampleelimination/ + * Copyright (c) 2016, Cem Yuksel <cem@cemyuksel.com> + * All rights reserved. + */ + +#include "BLI_inplace_priority_queue.hh" +#include "BLI_kdtree.h" + +#include "node_geometry_util.hh" + +#include <cstring> +#include <iostream> + +namespace blender::nodes { + +static void tile_point(Vector<float3> *tiled_points, + Vector<size_t> *indices, + const float maximum_distance, + const float3 boundbox, + float3 const &point, + size_t index, + int dimension = 0) +{ + for (int dimension_iter = dimension; dimension_iter < 3; dimension_iter++) { + if (boundbox[dimension_iter] - point[dimension_iter] < maximum_distance) { + float3 point_tiled = point; + point_tiled[dimension_iter] -= boundbox[dimension_iter]; + + tiled_points->append(point_tiled); + indices->append(index); + + tile_point(tiled_points, + indices, + maximum_distance, + boundbox, + point_tiled, + index, + dimension_iter + 1); + } + + if (point[dimension_iter] < maximum_distance) { + float3 point_tiled = point; + point_tiled[dimension_iter] += boundbox[dimension_iter]; + + tiled_points->append(point_tiled); + indices->append(index); + + tile_point(tiled_points, + indices, + maximum_distance, + boundbox, + point_tiled, + index, + dimension_iter + 1); + } + } +} + +/** + * Returns the weight the point gets based on the distance to another point. + */ +static float point_weight_influence_get(const float maximum_distance, + const float minimum_distance, + float distance) +{ + const float alpha = 8.0f; + + if (distance < minimum_distance) { + distance = minimum_distance; + } + + return std::pow(1.0f - distance / maximum_distance, alpha); +} + +/** + * Weight each point based on their proximity to its neighbors + * + * For each index in the weight array add a weight based on the proximity the + * corresponding point has with its neighboors. + **/ +static void points_distance_weight_calculate(Vector<float> *weights, + const size_t point_id, + const float3 *input_points, + const void *kd_tree, + const float minimum_distance, + const float maximum_distance, + InplacePriorityQueue<float> *heap) +{ + KDTreeNearest_3d *nearest_point = nullptr; + int neighbors = BLI_kdtree_3d_range_search( + (KDTree_3d *)kd_tree, input_points[point_id], &nearest_point, maximum_distance); + + for (int i = 0; i < neighbors; i++) { + size_t neighbor_point_id = nearest_point[i].index; + + if (neighbor_point_id >= weights->size()) { + continue; + } + + /* The point should not influence itself. */ + if (neighbor_point_id == point_id) { + continue; + } + + const float weight_influence = point_weight_influence_get( + maximum_distance, minimum_distance, nearest_point[i].dist); + + /* In the first pass we just the weights. */ + if (heap == nullptr) { + (*weights)[point_id] += weight_influence; + } + /* When we run again we need to update the weights and the heap. */ + else { + (*weights)[neighbor_point_id] -= weight_influence; + heap->priority_decreased(neighbor_point_id); + } + } + + if (nearest_point) { + MEM_freeN(nearest_point); + } +} + +/** + * Returns the minimum radius fraction used by the default weight function. + */ +static float weight_limit_fraction_get(const size_t input_size, const size_t output_size) +{ + const float beta = 0.65f; + const float gamma = 1.5f; + float ratio = float(output_size) / float(input_size); + return (1.0f - std::pow(ratio, gamma)) * beta; +} + +/** + * Tile the input points. + */ +static void points_tiling(const float3 *input_points, + const size_t input_size, + void **kd_tree, + const float maximum_distance, + const float3 boundbox) + +{ + Vector<float3> tiled_points(input_points, input_points + input_size); + Vector<size_t> indices(input_size); + + for (size_t i = 0; i < input_size; i++) { + indices[i] = i; + } + + /* Tile the tree based on the boundbox. */ + for (size_t i = 0; i < input_size; i++) { + tile_point(&tiled_points, &indices, maximum_distance, boundbox, input_points[i], i); + } + + /* Build a new tree with the new indices and tiled points. */ + *kd_tree = BLI_kdtree_3d_new(tiled_points.size()); + for (size_t i = 0; i < tiled_points.size(); i++) { + BLI_kdtree_3d_insert(*(KDTree_3d **)kd_tree, indices[i], tiled_points[i]); + } + BLI_kdtree_3d_balance(*(KDTree_3d **)kd_tree); +} + +static void weighted_sample_elimination(const float3 *input_points, + const size_t input_size, + float3 *output_points, + const size_t output_size, + const float maximum_distance, + const float3 boundbox, + const bool do_copy_eliminated) +{ + const float minimum_distance = maximum_distance * + weight_limit_fraction_get(input_size, output_size); + + void *kd_tree = nullptr; + points_tiling(input_points, input_size, &kd_tree, maximum_distance, boundbox); + + /* Assign weights to each sample. */ + Vector<float> weights(input_size, 0.0f); + for (size_t point_id = 0; point_id < weights.size(); point_id++) { + points_distance_weight_calculate( + &weights, point_id, input_points, kd_tree, minimum_distance, maximum_distance, nullptr); + } + + /* Remove the points based on their weight. */ + InplacePriorityQueue<float> heap(weights); + + size_t sample_size = input_size; + while (sample_size > output_size) { + /* For each sample around it, remove its weight contribution and update the heap. */ + size_t point_id = heap.pop_index(); + points_distance_weight_calculate( + &weights, point_id, input_points, kd_tree, minimum_distance, maximum_distance, &heap); + sample_size--; + } + + /* Copy the samples to the output array. */ + size_t target_size = do_copy_eliminated ? input_size : output_size; + for (size_t i = 0; i < target_size; i++) { + size_t index = heap.all_indices()[i]; + output_points[i] = input_points[index]; + } + + /* Cleanup. */ + BLI_kdtree_3d_free((KDTree_3d *)kd_tree); +} + +static void progressive_sampling_reorder(Vector<float3> *output_points, + float maximum_density, + float3 boundbox) +{ + /* Re-order the points for progressive sampling. */ + Vector<float3> temporary_points(output_points->size()); + float3 *source_points = output_points->data(); + float3 *dest_points = temporary_points.data(); + size_t source_size = output_points->size(); + size_t dest_size = 0; + + while (source_size >= 3) { + dest_size = source_size * 0.5f; + + /* Changes the weight function radius using half of the number of samples. + * It is used for progressive sampling. */ + maximum_density *= std::sqrt(2.0f); + weighted_sample_elimination( + source_points, source_size, dest_points, dest_size, maximum_density, boundbox, true); + + if (dest_points != output_points->data()) { + memcpy((*output_points)[dest_size], + dest_points[dest_size], + (source_size - dest_size) * sizeof(float3)); + } + + /* Swap the arrays around. */ + float3 *points_iter = source_points; + source_points = dest_points; + dest_points = points_iter; + source_size = dest_size; + } + if (source_points != output_points->data()) { + memcpy(output_points->data(), source_points, dest_size * sizeof(float3)); + } +} + +void poisson_disk_point_elimination(Vector<float3> const *input_points, + Vector<float3> *output_points, + float maximum_density, + float3 boundbox) +{ + weighted_sample_elimination(input_points->data(), + input_points->size(), + output_points->data(), + output_points->size(), + maximum_density, + boundbox, + false); + + progressive_sampling_reorder(output_points, maximum_density, boundbox); +} + +} // namespace blender::nodes diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc b/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc index 6d979e3b7da..4274ded2024 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc @@ -16,15 +16,21 @@ #include "BKE_mesh.h" #include "BKE_persistent_data_handle.hh" + +#include "DNA_collection_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_pointcloud_types.h" +#include "BLI_hash.h" + #include "node_geometry_util.hh" static bNodeSocketTemplate geo_node_point_instance_in[] = { {SOCK_GEOMETRY, N_("Geometry")}, {SOCK_OBJECT, N_("Object")}, + {SOCK_COLLECTION, N_("Collection")}, + {SOCK_INT, N_("Seed"), 0, 0, 0, 0, -10000, 10000}, {-1, ""}, }; @@ -35,19 +41,129 @@ static bNodeSocketTemplate geo_node_point_instance_out[] = { namespace blender::nodes { +static void geo_node_point_instance_update(bNodeTree *UNUSED(tree), bNode *node) +{ + bNodeSocket *object_socket = (bNodeSocket *)BLI_findlink(&node->inputs, 1); + bNodeSocket *collection_socket = object_socket->next; + bNodeSocket *seed_socket = collection_socket->next; + + GeometryNodePointInstanceType type = (GeometryNodePointInstanceType)node->custom1; + const bool use_whole_collection = node->custom2 == 0; + + nodeSetSocketAvailability(object_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_OBJECT); + nodeSetSocketAvailability(collection_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION); + nodeSetSocketAvailability( + seed_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION && !use_whole_collection); +} + +static void get_instanced_data__object(const GeoNodeExecParams ¶ms, + MutableSpan<std::optional<InstancedData>> r_instances_data) +{ + bke::PersistentObjectHandle object_handle = params.get_input<bke::PersistentObjectHandle>( + "Object"); + Object *object = params.handle_map().lookup(object_handle); + if (object == params.self_object()) { + object = nullptr; + } + if (object != nullptr) { + InstancedData instance; + instance.type = INSTANCE_DATA_TYPE_OBJECT; + instance.data.object = object; + r_instances_data.fill(instance); + } +} + +static void get_instanced_data__collection( + const GeoNodeExecParams ¶ms, + const GeometryComponent &component, + MutableSpan<std::optional<InstancedData>> r_instances_data) +{ + const bNode &node = params.node(); + bke::PersistentCollectionHandle collection_handle = + params.get_input<bke::PersistentCollectionHandle>("Collection"); + Collection *collection = params.handle_map().lookup(collection_handle); + if (collection != nullptr) { + const bool use_whole_collection = node.custom2 == 0; + if (use_whole_collection) { + InstancedData instance; + instance.type = INSTANCE_DATA_TYPE_COLLECTION; + instance.data.collection = collection; + r_instances_data.fill(instance); + } + else { + Vector<InstancedData> possible_instances; + /* Direct child objects are instanced as objects. */ + LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) { + Object *object = cob->ob; + InstancedData instance; + instance.type = INSTANCE_DATA_TYPE_OBJECT; + instance.data.object = object; + possible_instances.append(instance); + } + /* Direct child collections are instanced as collections. */ + LISTBASE_FOREACH (CollectionChild *, child, &collection->children) { + Collection *child_collection = child->collection; + InstancedData instance; + instance.type = INSTANCE_DATA_TYPE_COLLECTION; + instance.data.collection = child_collection; + possible_instances.append(instance); + } + + if (!possible_instances.is_empty()) { + const int seed = params.get_input<int>("Seed"); + Array<uint32_t> ids = get_geometry_element_ids_as_uints(component, ATTR_DOMAIN_POINT); + for (const int i : r_instances_data.index_range()) { + const int index = BLI_hash_int_2d(ids[i], seed) % possible_instances.size(); + r_instances_data[i] = possible_instances[index]; + } + } + } + } +} + +static Array<std::optional<InstancedData>> get_instanced_data(const GeoNodeExecParams ¶ms, + const GeometryComponent &component, + const int amount) +{ + const bNode &node = params.node(); + const GeometryNodePointInstanceType type = (GeometryNodePointInstanceType)node.custom1; + + Array<std::optional<InstancedData>> instances_data(amount); + + switch (type) { + case GEO_NODE_POINT_INSTANCE_TYPE_OBJECT: { + get_instanced_data__object(params, instances_data); + break; + } + case GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION: { + get_instanced_data__collection(params, component, instances_data); + break; + } + } + return instances_data; +} + static void add_instances_from_geometry_component(InstancesComponent &instances, const GeometryComponent &src_geometry, - Object *object) + const GeoNodeExecParams ¶ms) { + const AttributeDomain domain = ATTR_DOMAIN_POINT; + + const int domain_size = src_geometry.attribute_domain_size(domain); + Array<std::optional<InstancedData>> instances_data = get_instanced_data( + params, src_geometry, domain_size); + Float3ReadAttribute positions = src_geometry.attribute_get_for_read<float3>( - "position", ATTR_DOMAIN_POINT, {0, 0, 0}); + "position", domain, {0, 0, 0}); Float3ReadAttribute rotations = src_geometry.attribute_get_for_read<float3>( - "rotation", ATTR_DOMAIN_POINT, {0, 0, 0}); + "rotation", domain, {0, 0, 0}); Float3ReadAttribute scales = src_geometry.attribute_get_for_read<float3>( - "scale", ATTR_DOMAIN_POINT, {1, 1, 1}); + "scale", domain, {1, 1, 1}); - for (const int i : IndexRange(positions.size())) { - instances.add_instance(object, positions[i], rotations[i], scales[i]); + for (const int i : IndexRange(domain_size)) { + if (instances_data[i].has_value()) { + instances.add_instance(*instances_data[i], positions[i], rotations[i], scales[i]); + } } } @@ -56,20 +172,14 @@ static void geo_node_point_instance_exec(GeoNodeExecParams params) GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); GeometrySet geometry_set_out; - bke::PersistentObjectHandle object_handle = params.extract_input<bke::PersistentObjectHandle>( - "Object"); - Object *object = params.handle_map().lookup(object_handle); - - if (object != nullptr && object != params.self_object()) { - InstancesComponent &instances = geometry_set_out.get_component_for_write<InstancesComponent>(); - if (geometry_set.has<MeshComponent>()) { - add_instances_from_geometry_component( - instances, *geometry_set.get_component_for_read<MeshComponent>(), object); - } - if (geometry_set.has<PointCloudComponent>()) { - add_instances_from_geometry_component( - instances, *geometry_set.get_component_for_read<PointCloudComponent>(), object); - } + InstancesComponent &instances = geometry_set_out.get_component_for_write<InstancesComponent>(); + if (geometry_set.has<MeshComponent>()) { + add_instances_from_geometry_component( + instances, *geometry_set.get_component_for_read<MeshComponent>(), params); + } + if (geometry_set.has<PointCloudComponent>()) { + add_instances_from_geometry_component( + instances, *geometry_set.get_component_for_read<PointCloudComponent>(), params); } params.set_output("Geometry", std::move(geometry_set_out)); @@ -82,6 +192,7 @@ void register_node_type_geo_point_instance() geo_node_type_base(&ntype, GEO_NODE_POINT_INSTANCE, "Point Instance", NODE_CLASS_GEOMETRY, 0); node_type_socket_templates(&ntype, geo_node_point_instance_in, geo_node_point_instance_out); + node_type_update(&ntype, blender::nodes::geo_node_point_instance_update); ntype.geometry_node_execute = blender::nodes::geo_node_point_instance_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_separate.cc b/source/blender/nodes/geometry/nodes/node_geo_point_separate.cc new file mode 100644 index 00000000000..3229d87e1b2 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_point_separate.cc @@ -0,0 +1,212 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "BKE_mesh.h" +#include "BKE_persistent_data_handle.hh" +#include "BKE_pointcloud.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_pointcloud_types.h" + +#include "node_geometry_util.hh" + +static bNodeSocketTemplate geo_node_point_instance_in[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {SOCK_STRING, N_("Mask")}, + {-1, ""}, +}; + +static bNodeSocketTemplate geo_node_point_instance_out[] = { + {SOCK_GEOMETRY, N_("Geometry 1")}, + {SOCK_GEOMETRY, N_("Geometry 2")}, + {-1, ""}, +}; + +namespace blender::nodes { + +static void fill_new_attribute_from_input(ReadAttributePtr input_attribute, + WriteAttributePtr out_attribute_a, + WriteAttributePtr out_attribute_b, + Span<bool> a_or_b) +{ + fn::GSpan in_span = input_attribute->get_span(); + int i_a = 0; + int i_b = 0; + for (int i_in = 0; i_in < in_span.size(); i_in++) { + const bool move_to_b = a_or_b[i_in]; + if (move_to_b) { + out_attribute_b->set(i_b, in_span[i_in]); + i_b++; + } + else { + out_attribute_a->set(i_a, in_span[i_in]); + i_a++; + } + } +} + +/** + * Move the original attribute values to the two output components. + * + * \note This assumes a consistent ordering of indices before and after the split, + * which is true for points and a simple vertex array. + */ +static void move_split_attributes(const GeometryComponent &in_component, + GeometryComponent &out_component_a, + GeometryComponent &out_component_b, + Span<bool> a_or_b) +{ + Set<std::string> attribute_names = in_component.attribute_names(); + + for (const std::string &name : attribute_names) { + ReadAttributePtr attribute = in_component.attribute_try_get_for_read(name); + BLI_assert(attribute); + + /* Since this node only creates points and vertices, don't copy other attributes. */ + if (attribute->domain() != ATTR_DOMAIN_POINT) { + continue; + } + + const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute->cpp_type()); + const AttributeDomain domain = attribute->domain(); + + /* Don't try to create the attribute on the new component if it already exists. Built-in + * attributes will already exist on new components by definition. It should always be possible + * to recreate the attribute on the same component type. Also, if one of the new components + * has the attribute the other one should have it too, but check independently to be safe. */ + if (!out_component_a.attribute_exists(name)) { + if (!out_component_a.attribute_try_create(name, domain, data_type)) { + BLI_assert(false); + continue; + } + } + if (!out_component_b.attribute_exists(name)) { + if (!out_component_b.attribute_try_create(name, domain, data_type)) { + BLI_assert(false); + continue; + } + } + + WriteAttributePtr out_attribute_a = out_component_a.attribute_try_get_for_write(name); + WriteAttributePtr out_attribute_b = out_component_b.attribute_try_get_for_write(name); + if (!out_attribute_a || !out_attribute_b) { + BLI_assert(false); + continue; + } + + fill_new_attribute_from_input( + std::move(attribute), std::move(out_attribute_a), std::move(out_attribute_b), a_or_b); + } +} + +/** + * Find total in each new set and find which of the output sets each point will belong to. + */ +static Array<bool> count_point_splits(const GeometryComponent &component, + const GeoNodeExecParams ¶ms, + int *r_a_total, + int *r_b_total) +{ + const BooleanReadAttribute mask_attribute = params.get_input_attribute<bool>( + "Mask", component, ATTR_DOMAIN_POINT, false); + Array<bool> masks = mask_attribute.get_span(); + const int in_total = masks.size(); + + *r_b_total = 0; + for (const bool mask : masks) { + if (mask) { + *r_b_total += 1; + } + } + *r_a_total = in_total - *r_b_total; + + return masks; +} + +static void separate_mesh(const MeshComponent &in_component, + const GeoNodeExecParams ¶ms, + MeshComponent &out_component_a, + MeshComponent &out_component_b) +{ + const int size = in_component.attribute_domain_size(ATTR_DOMAIN_POINT); + if (size == 0) { + return; + } + + int a_total; + int b_total; + Array<bool> a_or_b = count_point_splits(in_component, params, &a_total, &b_total); + + out_component_a.replace(BKE_mesh_new_nomain(a_total, 0, 0, 0, 0)); + out_component_b.replace(BKE_mesh_new_nomain(b_total, 0, 0, 0, 0)); + + move_split_attributes(in_component, out_component_a, out_component_b, a_or_b); +} + +static void separate_point_cloud(const PointCloudComponent &in_component, + const GeoNodeExecParams ¶ms, + PointCloudComponent &out_component_a, + PointCloudComponent &out_component_b) +{ + const int size = in_component.attribute_domain_size(ATTR_DOMAIN_POINT); + if (size == 0) { + return; + } + + int a_total; + int b_total; + Array<bool> a_or_b = count_point_splits(in_component, params, &a_total, &b_total); + + out_component_a.replace(BKE_pointcloud_new_nomain(a_total)); + out_component_b.replace(BKE_pointcloud_new_nomain(b_total)); + + move_split_attributes(in_component, out_component_a, out_component_b, a_or_b); +} + +static void geo_node_point_separate_exec(GeoNodeExecParams params) +{ + GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); + GeometrySet out_set_a(geometry_set); + GeometrySet out_set_b; + + if (geometry_set.has<PointCloudComponent>()) { + separate_point_cloud(*geometry_set.get_component_for_read<PointCloudComponent>(), + params, + out_set_a.get_component_for_write<PointCloudComponent>(), + out_set_b.get_component_for_write<PointCloudComponent>()); + } + if (geometry_set.has<MeshComponent>()) { + separate_mesh(*geometry_set.get_component_for_read<MeshComponent>(), + params, + out_set_a.get_component_for_write<MeshComponent>(), + out_set_b.get_component_for_write<MeshComponent>()); + } + + params.set_output("Geometry 1", std::move(out_set_a)); + params.set_output("Geometry 2", std::move(out_set_b)); +} +} // namespace blender::nodes + +void register_node_type_geo_point_separate() +{ + static bNodeType ntype; + + geo_node_type_base(&ntype, GEO_NODE_POINT_SEPARATE, "Point Separate", NODE_CLASS_GEOMETRY, 0); + node_type_socket_templates(&ntype, geo_node_point_instance_in, geo_node_point_instance_out); + ntype.geometry_node_execute = blender::nodes::geo_node_point_separate_exec; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc index e5e7cf57e27..543859aef3f 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc @@ -16,6 +16,7 @@ #include "MEM_guardedalloc.h" +#include "BKE_mesh.h" #include "BKE_subdiv.h" #include "BKE_subdiv_mesh.h" @@ -25,7 +26,7 @@ static bNodeSocketTemplate geo_node_subdivision_surface_in[] = { {SOCK_GEOMETRY, N_("Geometry")}, {SOCK_INT, N_("Level"), 1, 0, 0, 0, 0, 6}, {SOCK_BOOLEAN, N_("Use Creases")}, - {SOCK_BOOLEAN, N_("Boundary Smooth")}, + {SOCK_BOOLEAN, N_("Boundary Smooth"), true}, {SOCK_BOOLEAN, N_("Smooth UVs")}, {-1, ""}, }; @@ -76,7 +77,7 @@ static void geo_node_subdivision_surface_exec(GeoNodeExecParams params) subdiv_settings.level = subdiv_level; subdiv_settings.vtx_boundary_interpolation = BKE_subdiv_vtx_boundary_interpolation_from_subsurf( - boundary_smooth); + !boundary_smooth); subdiv_settings.fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth( smooth_uvs); @@ -90,6 +91,7 @@ static void geo_node_subdivision_surface_exec(GeoNodeExecParams params) } Mesh *mesh_out = BKE_subdiv_to_mesh(subdiv, &mesh_settings, mesh_in); + BKE_mesh_calc_normals(mesh_out); geometry_set.replace_mesh(mesh_out); diff --git a/source/blender/nodes/intern/math_functions.cc b/source/blender/nodes/intern/math_functions.cc index cc5e9547a96..32a18f1c193 100644 --- a/source/blender/nodes/intern/math_functions.cc +++ b/source/blender/nodes/intern/math_functions.cc @@ -41,6 +41,8 @@ const FloatMathOperationInfo *get_float_math_operation_info(const int operation) RETURN_OPERATION_INFO("Sine", "math_sine"); case NODE_MATH_COSINE: RETURN_OPERATION_INFO("Cosine", "math_cosine"); + case NODE_MATH_TANGENT: + RETURN_OPERATION_INFO("Tangent", "math_tangent"); case NODE_MATH_ARCSINE: RETURN_OPERATION_INFO("Arc Sine", "math_arcsine"); case NODE_MATH_ARCCOSINE: @@ -114,4 +116,34 @@ const FloatMathOperationInfo *get_float_math_operation_info(const int operation) return nullptr; } +const FloatMathOperationInfo *get_float_compare_operation_info(const int operation) +{ + +#define RETURN_OPERATION_INFO(title_case_name, shader_name) \ + { \ + static const FloatMathOperationInfo info{title_case_name, shader_name}; \ + return &info; \ + } \ + ((void)0) + + switch (operation) { + case NODE_FLOAT_COMPARE_LESS_THAN: + RETURN_OPERATION_INFO("Less Than", "math_less_than"); + case NODE_FLOAT_COMPARE_LESS_EQUAL: + RETURN_OPERATION_INFO("Less Than or Equal", "math_less_equal"); + case NODE_FLOAT_COMPARE_GREATER_THAN: + RETURN_OPERATION_INFO("Greater Than", "math_greater_than"); + case NODE_FLOAT_COMPARE_GREATER_EQUAL: + RETURN_OPERATION_INFO("Greater Than or Equal", "math_greater_equal"); + case NODE_FLOAT_COMPARE_EQUAL: + RETURN_OPERATION_INFO("Equal", "math_equal"); + case NODE_FLOAT_COMPARE_NOT_EQUAL: + RETURN_OPERATION_INFO("Not Equal", "math_not_equal"); + } + +#undef RETURN_OPERATION_INFO + + return nullptr; +} + } // namespace blender::nodes diff --git a/source/blender/nodes/intern/node_exec.c b/source/blender/nodes/intern/node_exec.c index 85c408c40bb..0d46119ab60 100644 --- a/source/blender/nodes/intern/node_exec.c +++ b/source/blender/nodes/intern/node_exec.c @@ -186,8 +186,6 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context, for (n = 0; n < totnodes; n++) { node = nodelist[n]; - node->stack_index = index; - /* init node socket stack indexes */ for (sock = node->inputs.first; sock; sock = sock->next) { node_init_input_index(sock, &index); diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc index 50292cb8cfb..eef2c6c9125 100644 --- a/source/blender/nodes/intern/node_geometry_exec.cc +++ b/source/blender/nodes/intern/node_geometry_exec.cc @@ -19,6 +19,91 @@ namespace blender::nodes { +const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name) const +{ + LISTBASE_FOREACH (const bNodeSocket *, socket, &node_.inputs) { + if ((socket->flag & SOCK_UNAVAIL) != 0) { + continue; + } + if (name == socket->name) { + return socket; + } + } + + return nullptr; +} + +ReadAttributePtr GeoNodeExecParams::get_input_attribute(const StringRef name, + const GeometryComponent &component, + const AttributeDomain domain, + const CustomDataType type, + const void *default_value) const +{ + const bNodeSocket *found_socket = this->find_available_socket(name); + BLI_assert(found_socket != nullptr); /* There should always be available socket for the name. */ + if (found_socket == nullptr) { + return component.attribute_get_constant_for_read(domain, type, default_value); + } + + if (found_socket->type == SOCK_STRING) { + const std::string name = this->get_input<std::string>(found_socket->identifier); + return component.attribute_get_for_read(name, domain, type, default_value); + } + if (found_socket->type == SOCK_FLOAT) { + const float value = this->get_input<float>(found_socket->identifier); + return component.attribute_get_constant_for_read_converted( + domain, CD_PROP_FLOAT, type, &value); + } + if (found_socket->type == SOCK_VECTOR) { + const float3 value = this->get_input<float3>(found_socket->identifier); + return component.attribute_get_constant_for_read_converted( + domain, CD_PROP_FLOAT3, type, &value); + } + if (found_socket->type == SOCK_RGBA) { + const Color4f value = this->get_input<Color4f>(found_socket->identifier); + return component.attribute_get_constant_for_read_converted( + domain, CD_PROP_COLOR, type, &value); + } + BLI_assert(false); + return component.attribute_get_constant_for_read(domain, type, default_value); +} + +CustomDataType GeoNodeExecParams::get_input_attribute_data_type( + const StringRef name, + const GeometryComponent &component, + const CustomDataType default_type) const +{ + const bNodeSocket *found_socket = this->find_available_socket(name); + BLI_assert(found_socket != nullptr); /* There should always be available socket for the name. */ + if (found_socket == nullptr) { + return default_type; + } + + if (found_socket->type == SOCK_STRING) { + const std::string name = this->get_input<std::string>(found_socket->identifier); + ReadAttributePtr attribute = component.attribute_try_get_for_read(name); + if (!attribute) { + return default_type; + } + return attribute->custom_data_type(); + } + if (found_socket->type == SOCK_FLOAT) { + return CD_PROP_FLOAT; + } + if (found_socket->type == SOCK_VECTOR) { + return CD_PROP_FLOAT3; + } + if (found_socket->type == SOCK_RGBA) { + return CD_PROP_COLOR; + } + if (found_socket->type == SOCK_BOOLEAN) { + return CD_PROP_BOOL; + } + + BLI_assert(false); + return default_type; +} + void GeoNodeExecParams::check_extract_input(StringRef identifier, const CPPType *requested_type) const { diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc index ebc70956147..60c2d6c37e1 100644 --- a/source/blender/nodes/intern/node_socket.cc +++ b/source/blender/nodes/intern/node_socket.cc @@ -37,6 +37,8 @@ #include "BKE_node.h" #include "BKE_persistent_data_handle.hh" +#include "DNA_collection_types.h" + #include "RNA_access.h" #include "RNA_types.h" @@ -280,6 +282,15 @@ void node_socket_init_default_value(bNodeSocket *sock) sock->default_value = dval; break; } + case SOCK_COLLECTION: { + bNodeSocketValueCollection *dval = (bNodeSocketValueCollection *)MEM_callocN( + sizeof(bNodeSocketValueCollection), "node socket value object"); + dval->value = nullptr; + + sock->default_value = dval; + break; + break; + } } } @@ -352,6 +363,13 @@ void node_socket_copy_default_value(bNodeSocket *to, const bNodeSocket *from) id_us_plus(&toval->value->id); break; } + case SOCK_COLLECTION: { + bNodeSocketValueCollection *toval = (bNodeSocketValueCollection *)to->default_value; + bNodeSocketValueCollection *fromval = (bNodeSocketValueCollection *)from->default_value; + *toval = *fromval; + id_us_plus(&toval->value->id); + break; + } } to->flag |= (from->flag & SOCK_HIDE_VALUE); @@ -648,6 +666,7 @@ class ObjectSocketMultiFunction : public blender::fn::MultiFunction { }; MAKE_CPP_TYPE(PersistentObjectHandle, blender::bke::PersistentObjectHandle); +MAKE_CPP_TYPE(PersistentCollectionHandle, blender::bke::PersistentCollectionHandle); static bNodeSocketType *make_socket_type_object() { @@ -673,6 +692,16 @@ static bNodeSocketType *make_socket_type_geometry() return socktype; } +static bNodeSocketType *make_socket_type_collection() +{ + bNodeSocketType *socktype = make_standard_socket_type(SOCK_COLLECTION, PROP_NONE); + socktype->get_cpp_type = []() { + /* Objects are not passed along as raw pointers, but as handles. */ + return &blender::fn::CPPType::get<blender::bke::PersistentCollectionHandle>(); + }; + return socktype; +} + void register_standard_node_socket_types(void) { /* draw callbacks are set in drawnode.c to avoid bad-level calls */ @@ -711,5 +740,7 @@ void register_standard_node_socket_types(void) nodeRegisterSocketType(make_socket_type_geometry()); + nodeRegisterSocketType(make_socket_type_collection()); + nodeRegisterSocketType(make_socket_type_virtual()); } diff --git a/source/blender/nodes/intern/node_tree_multi_function.cc b/source/blender/nodes/intern/node_tree_multi_function.cc index ec5527a2970..2e4196af156 100644 --- a/source/blender/nodes/intern/node_tree_multi_function.cc +++ b/source/blender/nodes/intern/node_tree_multi_function.cc @@ -208,6 +208,10 @@ static DataTypeConversions create_implicit_conversions() conversions, "float to Color4f", [](float a) { return Color4f(a, a, a, 1.0f); }); add_implicit_conversion<Color4f, float>( conversions, "Color4f to float", [](Color4f a) { return rgb_to_grayscale(a); }); + add_implicit_conversion<float3, bool>( + conversions, "float3 to boolean", [](float3 a) { return a.length_squared() == 0.0f; }); + add_implicit_conversion<bool, float3>( + conversions, "boolean to float3", [](bool a) { return (a) ? float3(1.0f) : float3(0.0f); }); return conversions; } diff --git a/source/blender/nodes/intern/node_util.c b/source/blender/nodes/intern/node_util.c index 123347afc19..9669dc6496b 100644 --- a/source/blender/nodes/intern/node_util.c +++ b/source/blender/nodes/intern/node_util.c @@ -451,6 +451,14 @@ static int node_datatype_priority(eNodeSocketDatatype from, eNodeSocketDatatype return -1; } } + case SOCK_COLLECTION: { + switch (from) { + case SOCK_COLLECTION: + return 1; + default: + return -1; + } + } default: return -1; } diff --git a/source/blender/nodes/shader/nodes/node_shader_clamp.cc b/source/blender/nodes/shader/nodes/node_shader_clamp.cc index d3a893e1d76..4f77421cfe0 100644 --- a/source/blender/nodes/shader/nodes/node_shader_clamp.cc +++ b/source/blender/nodes/shader/nodes/node_shader_clamp.cc @@ -46,8 +46,9 @@ static int gpu_shader_clamp(GPUMaterial *mat, GPUNodeStack *in, GPUNodeStack *out) { - return (node->custom1 == NODE_CLAMP_MINMAX) ? GPU_stack_link(mat, node, "clamp_value", in, out) : - GPU_stack_link(mat, node, "clamp_range", in, out); + return (node->custom1 == NODE_CLAMP_MINMAX) ? + GPU_stack_link(mat, node, "clamp_minmax", in, out) : + GPU_stack_link(mat, node, "clamp_range", in, out); } static void sh_node_clamp_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder) diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h index 46b4dbc96d7..366d801a888 100644 --- a/source/blender/python/BPY_extern.h +++ b/source/blender/python/BPY_extern.h @@ -26,7 +26,6 @@ struct ID; /* DNA_ID.h */ struct ListBase; /* DNA_listBase.h */ struct Object; /* DNA_object_types.h */ struct PathResolvedRNA; -struct ReportList; struct Text; /* defined in DNA_text_types.h */ struct bConstraint; /* DNA_constraint_types.h */ struct bConstraintOb; /* DNA_constraint_types.h */ diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c index a8b66f3f2fe..fd996c8a1a2 100644 --- a/source/blender/python/generic/idprop_py_api.c +++ b/source/blender/python/generic/idprop_py_api.c @@ -20,8 +20,6 @@ #include <Python.h> -#include <string.h> - #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" @@ -30,6 +28,8 @@ #include "BKE_idprop.h" +#include "DNA_ID.h" /* ID property definitions. */ + #define USE_STRING_COERCE #ifdef USE_STRING_COERCE @@ -255,7 +255,7 @@ static int BPy_IDGroup_SetName(BPy_IDProperty *self, PyObject *value, void *UNUS name = _PyUnicode_AsStringAndSize(value, &name_size); - if (name_size > MAX_IDPROP_NAME) { + if (name_size >= MAX_IDPROP_NAME) { PyErr_SetString(PyExc_TypeError, "string length cannot exceed 63 characters!"); return -1; } @@ -367,16 +367,11 @@ static const char *idp_try_read_name(PyObject *name_obj) return NULL; } - if (name_size > MAX_IDPROP_NAME) { + if (name_size >= MAX_IDPROP_NAME) { PyErr_SetString(PyExc_KeyError, "the length of IDProperty names is limited to 63 characters"); return NULL; } - - if (strchr(name, '\"') || strchr(name, '\\') || strchr(name, '\'')) { - PyErr_SetString(PyExc_KeyError, "IDProperty names cannot include \", \\, or \'"); - return NULL; - } } else { name = ""; diff --git a/source/blender/python/gpu/gpu_py_batch.c b/source/blender/python/gpu/gpu_py_batch.c index 81d1cb7055d..9fb7aea162a 100644 --- a/source/blender/python/gpu/gpu_py_batch.c +++ b/source/blender/python/gpu/gpu_py_batch.c @@ -48,7 +48,7 @@ /** \name Utility Functions * \{ */ -static bool bpygpu_batch_is_program_or_error(BPyGPUBatch *self) +static bool py_batch_is_program_or_error(BPyGPUBatch *self) { if (!self->batch->shader) { PyErr_SetString(PyExc_RuntimeError, "batch does not have any program assigned to it"); @@ -63,7 +63,7 @@ static bool bpygpu_batch_is_program_or_error(BPyGPUBatch *self) /** \name GPUBatch Type * \{ */ -static PyObject *bpygpu_Batch_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds) +static PyObject *py_Batch_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds) { BPYGPU_IS_INIT_OR_ERROR_OBJ; @@ -121,7 +121,7 @@ static PyObject *bpygpu_Batch_new(PyTypeObject *UNUSED(type), PyObject *args, Py return (PyObject *)ret; } -PyDoc_STRVAR(bpygpu_Batch_vertbuf_add_doc, +PyDoc_STRVAR(py_Batch_vertbuf_add_doc, ".. method:: vertbuf_add(buf)\n" "\n" " Add another vertex buffer to the Batch.\n" @@ -134,7 +134,7 @@ PyDoc_STRVAR(bpygpu_Batch_vertbuf_add_doc, " :param buf: The vertex buffer that will be added to the batch.\n" " :type buf: :class:`gpu.types.GPUVertBuf`\n" ); -static PyObject *bpygpu_Batch_vertbuf_add(BPyGPUBatch *self, BPyGPUVertBuf *py_buf) +static PyObject *py_Batch_vertbuf_add(BPyGPUBatch *self, BPyGPUVertBuf *py_buf) { if (!BPyGPUVertBuf_Check(py_buf)) { PyErr_Format(PyExc_TypeError, "Expected a GPUVertBuf, got %s", Py_TYPE(py_buf)->tp_name); @@ -167,7 +167,7 @@ static PyObject *bpygpu_Batch_vertbuf_add(BPyGPUBatch *self, BPyGPUVertBuf *py_b } PyDoc_STRVAR( - bpygpu_Batch_program_set_doc, + py_Batch_program_set_doc, ".. method:: program_set(program)\n" "\n" " Assign a shader to this batch that will be used for drawing when not overwritten later.\n" @@ -177,7 +177,7 @@ PyDoc_STRVAR( "\n" " :param program: The program/shader the batch will use in future draw calls.\n" " :type program: :class:`gpu.types.GPUShader`\n"); -static PyObject *bpygpu_Batch_program_set(BPyGPUBatch *self, BPyGPUShader *py_shader) +static PyObject *py_Batch_program_set(BPyGPUBatch *self, BPyGPUShader *py_shader) { if (!BPyGPUShader_Check(py_shader)) { PyErr_Format(PyExc_TypeError, "Expected a GPUShader, got %s", Py_TYPE(py_shader)->tp_name); @@ -208,7 +208,7 @@ static PyObject *bpygpu_Batch_program_set(BPyGPUBatch *self, BPyGPUShader *py_sh Py_RETURN_NONE; } -PyDoc_STRVAR(bpygpu_Batch_draw_doc, +PyDoc_STRVAR(py_Batch_draw_doc, ".. method:: draw(program=None)\n" "\n" " Run the drawing program with the parameters assigned to the batch.\n" @@ -216,7 +216,7 @@ PyDoc_STRVAR(bpygpu_Batch_draw_doc, " :param program: Program that performs the drawing operations.\n" " If ``None`` is passed, the last program set to this batch will run.\n" " :type program: :class:`gpu.types.GPUShader`\n"); -static PyObject *bpygpu_Batch_draw(BPyGPUBatch *self, PyObject *args) +static PyObject *py_Batch_draw(BPyGPUBatch *self, PyObject *args) { BPyGPUShader *py_program = NULL; @@ -224,7 +224,7 @@ static PyObject *bpygpu_Batch_draw(BPyGPUBatch *self, PyObject *args) return NULL; } if (py_program == NULL) { - if (!bpygpu_batch_is_program_or_error(self)) { + if (!py_batch_is_program_or_error(self)) { return NULL; } } @@ -236,42 +236,42 @@ static PyObject *bpygpu_Batch_draw(BPyGPUBatch *self, PyObject *args) Py_RETURN_NONE; } -static PyObject *bpygpu_Batch_program_use_begin(BPyGPUBatch *self) +static PyObject *py_Batch_program_use_begin(BPyGPUBatch *self) { - if (!bpygpu_batch_is_program_or_error(self)) { + if (!py_batch_is_program_or_error(self)) { return NULL; } GPU_shader_bind(self->batch->shader); Py_RETURN_NONE; } -static PyObject *bpygpu_Batch_program_use_end(BPyGPUBatch *self) +static PyObject *py_Batch_program_use_end(BPyGPUBatch *self) { - if (!bpygpu_batch_is_program_or_error(self)) { + if (!py_batch_is_program_or_error(self)) { return NULL; } GPU_shader_unbind(); Py_RETURN_NONE; } -static struct PyMethodDef bpygpu_Batch_methods[] = { - {"vertbuf_add", (PyCFunction)bpygpu_Batch_vertbuf_add, METH_O, bpygpu_Batch_vertbuf_add_doc}, - {"program_set", (PyCFunction)bpygpu_Batch_program_set, METH_O, bpygpu_Batch_program_set_doc}, - {"draw", (PyCFunction)bpygpu_Batch_draw, METH_VARARGS, bpygpu_Batch_draw_doc}, - {"_program_use_begin", (PyCFunction)bpygpu_Batch_program_use_begin, METH_NOARGS, ""}, - {"_program_use_end", (PyCFunction)bpygpu_Batch_program_use_end, METH_NOARGS, ""}, +static struct PyMethodDef py_Batch_methods[] = { + {"vertbuf_add", (PyCFunction)py_Batch_vertbuf_add, METH_O, py_Batch_vertbuf_add_doc}, + {"program_set", (PyCFunction)py_Batch_program_set, METH_O, py_Batch_program_set_doc}, + {"draw", (PyCFunction)py_Batch_draw, METH_VARARGS, py_Batch_draw_doc}, + {"_program_use_begin", (PyCFunction)py_Batch_program_use_begin, METH_NOARGS, ""}, + {"_program_use_end", (PyCFunction)py_Batch_program_use_end, METH_NOARGS, ""}, {NULL, NULL, 0, NULL}, }; #ifdef USE_GPU_PY_REFERENCES -static int bpygpu_Batch_traverse(BPyGPUBatch *self, visitproc visit, void *arg) +static int py_Batch_traverse(BPyGPUBatch *self, visitproc visit, void *arg) { Py_VISIT(self->references); return 0; } -static int bpygpu_Batch_clear(BPyGPUBatch *self) +static int py_Batch_clear(BPyGPUBatch *self) { Py_CLEAR(self->references); return 0; @@ -279,14 +279,14 @@ static int bpygpu_Batch_clear(BPyGPUBatch *self) #endif -static void bpygpu_Batch_dealloc(BPyGPUBatch *self) +static void py_Batch_dealloc(BPyGPUBatch *self) { GPU_batch_discard(self->batch); #ifdef USE_GPU_PY_REFERENCES if (self->references) { PyObject_GC_UnTrack(self); - bpygpu_Batch_clear(self); + py_Batch_clear(self); Py_XDECREF(self->references); } #endif @@ -319,17 +319,17 @@ PyDoc_STRVAR( PyTypeObject BPyGPUBatch_Type = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "GPUBatch", .tp_basicsize = sizeof(BPyGPUBatch), - .tp_dealloc = (destructor)bpygpu_Batch_dealloc, + .tp_dealloc = (destructor)py_Batch_dealloc, #ifdef USE_GPU_PY_REFERENCES .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, .tp_doc = py_gpu_batch_doc, - .tp_traverse = (traverseproc)bpygpu_Batch_traverse, - .tp_clear = (inquiry)bpygpu_Batch_clear, + .tp_traverse = (traverseproc)py_Batch_traverse, + .tp_clear = (inquiry)py_Batch_clear, #else .tp_flags = Py_TPFLAGS_DEFAULT, #endif - .tp_methods = bpygpu_Batch_methods, - .tp_new = bpygpu_Batch_new, + .tp_methods = py_Batch_methods, + .tp_new = py_Batch_new, }; /** \} */ diff --git a/source/blender/python/gpu/gpu_py_element.c b/source/blender/python/gpu/gpu_py_element.c index c863c9a586f..0a1aecde986 100644 --- a/source/blender/python/gpu/gpu_py_element.c +++ b/source/blender/python/gpu/gpu_py_element.c @@ -39,7 +39,7 @@ /** \name IndexBuf Type * \{ */ -static PyObject *bpygpu_IndexBuf_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds) +static PyObject *py_IndexBuf_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds) { BPYGPU_IS_INIT_OR_ERROR_OBJ; @@ -175,7 +175,7 @@ static PyObject *bpygpu_IndexBuf_new(PyTypeObject *UNUSED(type), PyObject *args, return BPyGPUIndexBuf_CreatePyObject(GPU_indexbuf_build(&builder)); } -static void bpygpu_IndexBuf_dealloc(BPyGPUIndexBuf *self) +static void py_IndexBuf_dealloc(BPyGPUIndexBuf *self) { GPU_indexbuf_discard(self->elem); Py_TYPE(self)->tp_free(self); @@ -199,10 +199,10 @@ PyDoc_STRVAR(py_gpu_element_doc, PyTypeObject BPyGPUIndexBuf_Type = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "GPUIndexBuf", .tp_basicsize = sizeof(BPyGPUIndexBuf), - .tp_dealloc = (destructor)bpygpu_IndexBuf_dealloc, + .tp_dealloc = (destructor)py_IndexBuf_dealloc, .tp_flags = Py_TPFLAGS_DEFAULT, .tp_doc = py_gpu_element_doc, - .tp_new = bpygpu_IndexBuf_new, + .tp_new = py_IndexBuf_new, }; /** \} */ diff --git a/source/blender/python/gpu/gpu_py_matrix.c b/source/blender/python/gpu/gpu_py_matrix.c index 93cca78bad9..a479f270770 100644 --- a/source/blender/python/gpu/gpu_py_matrix.c +++ b/source/blender/python/gpu/gpu_py_matrix.c @@ -44,7 +44,7 @@ /** \name Helper Functions * \{ */ -static bool bpygpu_stack_is_push_model_view_ok_or_error(void) +static bool py_stack_is_push_model_view_ok_or_error(void) { if (GPU_matrix_stack_level_get_model_view() >= GPU_PY_MATRIX_STACK_LEN) { PyErr_SetString( @@ -55,7 +55,7 @@ static bool bpygpu_stack_is_push_model_view_ok_or_error(void) return true; } -static bool bpygpu_stack_is_push_projection_ok_or_error(void) +static bool py_stack_is_push_projection_ok_or_error(void) { if (GPU_matrix_stack_level_get_projection() >= GPU_PY_MATRIX_STACK_LEN) { PyErr_SetString( @@ -66,7 +66,7 @@ static bool bpygpu_stack_is_push_projection_ok_or_error(void) return true; } -static bool bpygpu_stack_is_pop_model_view_ok_or_error(void) +static bool py_stack_is_pop_model_view_ok_or_error(void) { if (GPU_matrix_stack_level_get_model_view() == 0) { PyErr_SetString(PyExc_RuntimeError, "Minimum model-view stack depth reached"); @@ -75,7 +75,7 @@ static bool bpygpu_stack_is_pop_model_view_ok_or_error(void) return true; } -static bool bpygpu_stack_is_pop_projection_ok_or_error(void) +static bool py_stack_is_pop_projection_ok_or_error(void) { if (GPU_matrix_stack_level_get_projection() == 0) { PyErr_SetString(PyExc_RuntimeError, "Minimum projection stack depth reached"); @@ -90,52 +90,52 @@ static bool bpygpu_stack_is_pop_projection_ok_or_error(void) /** \name Manage Stack * \{ */ -PyDoc_STRVAR(bpygpu_matrix_push_doc, +PyDoc_STRVAR(py_matrix_push_doc, ".. function:: push()\n" "\n" " Add to the model-view matrix stack.\n"); -static PyObject *bpygpu_matrix_push(PyObject *UNUSED(self)) +static PyObject *py_matrix_push(PyObject *UNUSED(self)) { - if (!bpygpu_stack_is_push_model_view_ok_or_error()) { + if (!py_stack_is_push_model_view_ok_or_error()) { return NULL; } GPU_matrix_push(); Py_RETURN_NONE; } -PyDoc_STRVAR(bpygpu_matrix_pop_doc, +PyDoc_STRVAR(py_matrix_pop_doc, ".. function:: pop()\n" "\n" " Remove the last model-view matrix from the stack.\n"); -static PyObject *bpygpu_matrix_pop(PyObject *UNUSED(self)) +static PyObject *py_matrix_pop(PyObject *UNUSED(self)) { - if (!bpygpu_stack_is_pop_model_view_ok_or_error()) { + if (!py_stack_is_pop_model_view_ok_or_error()) { return NULL; } GPU_matrix_pop(); Py_RETURN_NONE; } -PyDoc_STRVAR(bpygpu_matrix_push_projection_doc, +PyDoc_STRVAR(py_matrix_push_projection_doc, ".. function:: push_projection()\n" "\n" " Add to the projection matrix stack.\n"); -static PyObject *bpygpu_matrix_push_projection(PyObject *UNUSED(self)) +static PyObject *py_matrix_push_projection(PyObject *UNUSED(self)) { - if (!bpygpu_stack_is_push_projection_ok_or_error()) { + if (!py_stack_is_push_projection_ok_or_error()) { return NULL; } GPU_matrix_push_projection(); Py_RETURN_NONE; } -PyDoc_STRVAR(bpygpu_matrix_pop_projection_doc, +PyDoc_STRVAR(py_matrix_pop_projection_doc, ".. function:: pop_projection()\n" "\n" " Remove the last projection matrix from the stack.\n"); -static PyObject *bpygpu_matrix_pop_projection(PyObject *UNUSED(self)) +static PyObject *py_matrix_pop_projection(PyObject *UNUSED(self)) { - if (!bpygpu_stack_is_pop_projection_ok_or_error()) { + if (!py_stack_is_pop_projection_ok_or_error()) { return NULL; } GPU_matrix_pop_projection(); @@ -162,12 +162,12 @@ enum { PYGPU_MATRIX_TYPE_PROJECTION = 2, }; -static PyObject *bpygpu_matrix_stack_context_enter(BPyGPU_MatrixStackContext *self); -static PyObject *bpygpu_matrix_stack_context_exit(BPyGPU_MatrixStackContext *self, PyObject *args); +static PyObject *py_matrix_stack_context_enter(BPyGPU_MatrixStackContext *self); +static PyObject *py_matrix_stack_context_exit(BPyGPU_MatrixStackContext *self, PyObject *args); -static PyMethodDef bpygpu_matrix_stack_context_methods[] = { - {"__enter__", (PyCFunction)bpygpu_matrix_stack_context_enter, METH_NOARGS}, - {"__exit__", (PyCFunction)bpygpu_matrix_stack_context_exit, METH_VARARGS}, +static PyMethodDef py_matrix_stack_context_methods[] = { + {"__enter__", (PyCFunction)py_matrix_stack_context_enter, METH_NOARGS}, + {"__exit__", (PyCFunction)py_matrix_stack_context_exit, METH_VARARGS}, {NULL}, }; @@ -175,10 +175,10 @@ static PyTypeObject BPyGPU_matrix_stack_context_Type = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "GPUMatrixStackContext", .tp_basicsize = sizeof(BPyGPU_MatrixStackContext), .tp_flags = Py_TPFLAGS_DEFAULT, - .tp_methods = bpygpu_matrix_stack_context_methods, + .tp_methods = py_matrix_stack_context_methods, }; -static PyObject *bpygpu_matrix_stack_context_enter(BPyGPU_MatrixStackContext *self) +static PyObject *py_matrix_stack_context_enter(BPyGPU_MatrixStackContext *self) { /* sanity - should never happen */ if (self->level != -1) { @@ -187,14 +187,14 @@ static PyObject *bpygpu_matrix_stack_context_enter(BPyGPU_MatrixStackContext *se } if (self->type == PYGPU_MATRIX_TYPE_MODEL_VIEW) { - if (!bpygpu_stack_is_push_model_view_ok_or_error()) { + if (!py_stack_is_push_model_view_ok_or_error()) { return NULL; } GPU_matrix_push(); self->level = GPU_matrix_stack_level_get_model_view(); } else if (self->type == PYGPU_MATRIX_TYPE_PROJECTION) { - if (!bpygpu_stack_is_push_projection_ok_or_error()) { + if (!py_stack_is_push_projection_ok_or_error()) { return NULL; } GPU_matrix_push_projection(); @@ -206,8 +206,8 @@ static PyObject *bpygpu_matrix_stack_context_enter(BPyGPU_MatrixStackContext *se Py_RETURN_NONE; } -static PyObject *bpygpu_matrix_stack_context_exit(BPyGPU_MatrixStackContext *self, - PyObject *UNUSED(args)) +static PyObject *py_matrix_stack_context_exit(BPyGPU_MatrixStackContext *self, + PyObject *UNUSED(args)) { /* sanity - should never happen */ if (self->level == -1) { @@ -240,7 +240,7 @@ finally: Py_RETURN_NONE; } -static PyObject *bpygpu_matrix_push_pop_impl(int type) +static PyObject *py_matrix_push_pop_impl(int type) { BPyGPU_MatrixStackContext *ret = PyObject_New(BPyGPU_MatrixStackContext, &BPyGPU_matrix_stack_context_Type); @@ -250,23 +250,23 @@ static PyObject *bpygpu_matrix_push_pop_impl(int type) } PyDoc_STRVAR( - bpygpu_matrix_push_pop_doc, + py_matrix_push_pop_doc, ".. function:: push_pop()\n" "\n" " Context manager to ensure balanced push/pop calls, even in the case of an error.\n"); -static PyObject *bpygpu_matrix_push_pop(PyObject *UNUSED(self)) +static PyObject *py_matrix_push_pop(PyObject *UNUSED(self)) { - return bpygpu_matrix_push_pop_impl(PYGPU_MATRIX_TYPE_MODEL_VIEW); + return py_matrix_push_pop_impl(PYGPU_MATRIX_TYPE_MODEL_VIEW); } PyDoc_STRVAR( - bpygpu_matrix_push_pop_projection_doc, + py_matrix_push_pop_projection_doc, ".. function:: push_pop_projection()\n" "\n" " Context manager to ensure balanced push/pop calls, even in the case of an error.\n"); -static PyObject *bpygpu_matrix_push_pop_projection(PyObject *UNUSED(self)) +static PyObject *py_matrix_push_pop_projection(PyObject *UNUSED(self)) { - return bpygpu_matrix_push_pop_impl(PYGPU_MATRIX_TYPE_PROJECTION); + return py_matrix_push_pop_impl(PYGPU_MATRIX_TYPE_PROJECTION); } /** \} */ @@ -275,14 +275,14 @@ static PyObject *bpygpu_matrix_push_pop_projection(PyObject *UNUSED(self)) /** \name Manipulate State * \{ */ -PyDoc_STRVAR(bpygpu_matrix_multiply_matrix_doc, +PyDoc_STRVAR(py_matrix_multiply_matrix_doc, ".. function:: multiply_matrix(matrix)\n" "\n" " Multiply the current stack matrix.\n" "\n" " :param matrix: A 4x4 matrix.\n" " :type matrix: :class:`mathutils.Matrix`\n"); -static PyObject *bpygpu_matrix_multiply_matrix(PyObject *UNUSED(self), PyObject *value) +static PyObject *py_matrix_multiply_matrix(PyObject *UNUSED(self), PyObject *value) { MatrixObject *pymat; if (!Matrix_Parse4x4(value, &pymat)) { @@ -292,14 +292,14 @@ static PyObject *bpygpu_matrix_multiply_matrix(PyObject *UNUSED(self), PyObject Py_RETURN_NONE; } -PyDoc_STRVAR(bpygpu_matrix_scale_doc, +PyDoc_STRVAR(py_matrix_scale_doc, ".. function:: scale(scale)\n" "\n" " Scale the current stack matrix.\n" "\n" " :param scale: Scale the current stack matrix.\n" " :type scale: sequence of 2 or 3 floats\n"); -static PyObject *bpygpu_matrix_scale(PyObject *UNUSED(self), PyObject *value) +static PyObject *py_matrix_scale(PyObject *UNUSED(self), PyObject *value) { float scale[3]; int len; @@ -316,12 +316,12 @@ static PyObject *bpygpu_matrix_scale(PyObject *UNUSED(self), PyObject *value) Py_RETURN_NONE; } -PyDoc_STRVAR(bpygpu_matrix_scale_uniform_doc, +PyDoc_STRVAR(py_matrix_scale_uniform_doc, ".. function:: scale_uniform(scale)\n" "\n" " :param scale: Scale the current stack matrix.\n" " :type scale: float\n"); -static PyObject *bpygpu_matrix_scale_uniform(PyObject *UNUSED(self), PyObject *value) +static PyObject *py_matrix_scale_uniform(PyObject *UNUSED(self), PyObject *value) { float scalar; if ((scalar = PyFloat_AsDouble(value)) == -1.0f && PyErr_Occurred()) { @@ -332,14 +332,14 @@ static PyObject *bpygpu_matrix_scale_uniform(PyObject *UNUSED(self), PyObject *v Py_RETURN_NONE; } -PyDoc_STRVAR(bpygpu_matrix_translate_doc, +PyDoc_STRVAR(py_matrix_translate_doc, ".. function:: translate(offset)\n" "\n" " Scale the current stack matrix.\n" "\n" " :param offset: Translate the current stack matrix.\n" " :type offset: sequence of 2 or 3 floats\n"); -static PyObject *bpygpu_matrix_translate(PyObject *UNUSED(self), PyObject *value) +static PyObject *py_matrix_translate(PyObject *UNUSED(self), PyObject *value) { float offset[3]; int len; @@ -362,34 +362,34 @@ static PyObject *bpygpu_matrix_translate(PyObject *UNUSED(self), PyObject *value /** \name Write State * \{ */ -PyDoc_STRVAR(bpygpu_matrix_reset_doc, +PyDoc_STRVAR(py_matrix_reset_doc, ".. function:: reset()\n" "\n" " Empty stack and set to identity.\n"); -static PyObject *bpygpu_matrix_reset(PyObject *UNUSED(self)) +static PyObject *py_matrix_reset(PyObject *UNUSED(self)) { GPU_matrix_reset(); Py_RETURN_NONE; } -PyDoc_STRVAR(bpygpu_matrix_load_identity_doc, +PyDoc_STRVAR(py_matrix_load_identity_doc, ".. function:: load_identity()\n" "\n" " Empty stack and set to identity.\n"); -static PyObject *bpygpu_matrix_load_identity(PyObject *UNUSED(self)) +static PyObject *py_matrix_load_identity(PyObject *UNUSED(self)) { GPU_matrix_identity_set(); Py_RETURN_NONE; } -PyDoc_STRVAR(bpygpu_matrix_load_matrix_doc, +PyDoc_STRVAR(py_matrix_load_matrix_doc, ".. function:: load_matrix(matrix)\n" "\n" " Load a matrix into the stack.\n" "\n" " :param matrix: A 4x4 matrix.\n" " :type matrix: :class:`mathutils.Matrix`\n"); -static PyObject *bpygpu_matrix_load_matrix(PyObject *UNUSED(self), PyObject *value) +static PyObject *py_matrix_load_matrix(PyObject *UNUSED(self), PyObject *value) { MatrixObject *pymat; if (!Matrix_Parse4x4(value, &pymat)) { @@ -399,14 +399,14 @@ static PyObject *bpygpu_matrix_load_matrix(PyObject *UNUSED(self), PyObject *val Py_RETURN_NONE; } -PyDoc_STRVAR(bpygpu_matrix_load_projection_matrix_doc, +PyDoc_STRVAR(py_matrix_load_projection_matrix_doc, ".. function:: load_projection_matrix(matrix)\n" "\n" " Load a projection matrix into the stack.\n" "\n" " :param matrix: A 4x4 matrix.\n" " :type matrix: :class:`mathutils.Matrix`\n"); -static PyObject *bpygpu_matrix_load_projection_matrix(PyObject *UNUSED(self), PyObject *value) +static PyObject *py_matrix_load_projection_matrix(PyObject *UNUSED(self), PyObject *value) { MatrixObject *pymat; if (!Matrix_Parse4x4(value, &pymat)) { @@ -422,42 +422,42 @@ static PyObject *bpygpu_matrix_load_projection_matrix(PyObject *UNUSED(self), Py /** \name Read State * \{ */ -PyDoc_STRVAR(bpygpu_matrix_get_projection_matrix_doc, +PyDoc_STRVAR(py_matrix_get_projection_matrix_doc, ".. function:: get_projection_matrix()\n" "\n" " Return a copy of the projection matrix.\n" "\n" " :return: A 4x4 projection matrix.\n" " :rtype: :class:`mathutils.Matrix`\n"); -static PyObject *bpygpu_matrix_get_projection_matrix(PyObject *UNUSED(self)) +static PyObject *py_matrix_get_projection_matrix(PyObject *UNUSED(self)) { float matrix[4][4]; GPU_matrix_projection_get(matrix); return Matrix_CreatePyObject(&matrix[0][0], 4, 4, NULL); } -PyDoc_STRVAR(bpygpu_matrix_get_model_view_matrix_doc, +PyDoc_STRVAR(py_matrix_get_model_view_matrix_doc, ".. function:: get_model_view_matrix()\n" "\n" " Return a copy of the model-view matrix.\n" "\n" " :return: A 4x4 view matrix.\n" " :rtype: :class:`mathutils.Matrix`\n"); -static PyObject *bpygpu_matrix_get_model_view_matrix(PyObject *UNUSED(self)) +static PyObject *py_matrix_get_model_view_matrix(PyObject *UNUSED(self)) { float matrix[4][4]; GPU_matrix_model_view_get(matrix); return Matrix_CreatePyObject(&matrix[0][0], 4, 4, NULL); } -PyDoc_STRVAR(bpygpu_matrix_get_normal_matrix_doc, +PyDoc_STRVAR(py_matrix_get_normal_matrix_doc, ".. function:: get_normal_matrix()\n" "\n" " Return a copy of the normal matrix.\n" "\n" " :return: A 3x3 normal matrix.\n" " :rtype: :class:`mathutils.Matrix`\n"); -static PyObject *bpygpu_matrix_get_normal_matrix(PyObject *UNUSED(self)) +static PyObject *py_matrix_get_normal_matrix(PyObject *UNUSED(self)) { float matrix[3][3]; GPU_matrix_normal_get(matrix); @@ -470,81 +470,78 @@ static PyObject *bpygpu_matrix_get_normal_matrix(PyObject *UNUSED(self)) /** \name Module * \{ */ -static struct PyMethodDef bpygpu_matrix_methods[] = { +static struct PyMethodDef py_matrix_methods[] = { /* Manage Stack */ - {"push", (PyCFunction)bpygpu_matrix_push, METH_NOARGS, bpygpu_matrix_push_doc}, - {"pop", (PyCFunction)bpygpu_matrix_pop, METH_NOARGS, bpygpu_matrix_pop_doc}, + {"push", (PyCFunction)py_matrix_push, METH_NOARGS, py_matrix_push_doc}, + {"pop", (PyCFunction)py_matrix_pop, METH_NOARGS, py_matrix_pop_doc}, {"push_projection", - (PyCFunction)bpygpu_matrix_push_projection, + (PyCFunction)py_matrix_push_projection, METH_NOARGS, - bpygpu_matrix_push_projection_doc}, + py_matrix_push_projection_doc}, {"pop_projection", - (PyCFunction)bpygpu_matrix_pop_projection, + (PyCFunction)py_matrix_pop_projection, METH_NOARGS, - bpygpu_matrix_pop_projection_doc}, + py_matrix_pop_projection_doc}, /* Stack (Context Manager) */ - {"push_pop", (PyCFunction)bpygpu_matrix_push_pop, METH_NOARGS, bpygpu_matrix_push_pop_doc}, + {"push_pop", (PyCFunction)py_matrix_push_pop, METH_NOARGS, py_matrix_push_pop_doc}, {"push_pop_projection", - (PyCFunction)bpygpu_matrix_push_pop_projection, + (PyCFunction)py_matrix_push_pop_projection, METH_NOARGS, - bpygpu_matrix_push_pop_projection_doc}, + py_matrix_push_pop_projection_doc}, /* Manipulate State */ {"multiply_matrix", - (PyCFunction)bpygpu_matrix_multiply_matrix, + (PyCFunction)py_matrix_multiply_matrix, METH_O, - bpygpu_matrix_multiply_matrix_doc}, - {"scale", (PyCFunction)bpygpu_matrix_scale, METH_O, bpygpu_matrix_scale_doc}, - {"scale_uniform", - (PyCFunction)bpygpu_matrix_scale_uniform, - METH_O, - bpygpu_matrix_scale_uniform_doc}, - {"translate", (PyCFunction)bpygpu_matrix_translate, METH_O, bpygpu_matrix_translate_doc}, + py_matrix_multiply_matrix_doc}, + {"scale", (PyCFunction)py_matrix_scale, METH_O, py_matrix_scale_doc}, + {"scale_uniform", (PyCFunction)py_matrix_scale_uniform, METH_O, py_matrix_scale_uniform_doc}, + {"translate", (PyCFunction)py_matrix_translate, METH_O, py_matrix_translate_doc}, /* TODO */ #if 0 - {"rotate", (PyCFunction)bpygpu_matrix_rotate, METH_O, bpygpu_matrix_rotate_doc}, - {"rotate_axis", (PyCFunction)bpygpu_matrix_rotate_axis, METH_O, bpygpu_matrix_rotate_axis_doc}, - {"look_at", (PyCFunction)bpygpu_matrix_look_at, METH_O, bpygpu_matrix_look_at_doc}, + {"rotate", (PyCFunction)py_matrix_rotate, METH_O, py_matrix_rotate_doc}, + {"rotate_axis", (PyCFunction)py_matrix_rotate_axis, METH_O, py_matrix_rotate_axis_doc}, + {"look_at", (PyCFunction)py_matrix_look_at, METH_O, py_matrix_look_at_doc}, #endif /* Write State */ - {"reset", (PyCFunction)bpygpu_matrix_reset, METH_NOARGS, bpygpu_matrix_reset_doc}, + {"reset", (PyCFunction)py_matrix_reset, METH_NOARGS, py_matrix_reset_doc}, {"load_identity", - (PyCFunction)bpygpu_matrix_load_identity, + (PyCFunction)py_matrix_load_identity, METH_NOARGS, - bpygpu_matrix_load_identity_doc}, - {"load_matrix", (PyCFunction)bpygpu_matrix_load_matrix, METH_O, bpygpu_matrix_load_matrix_doc}, + py_matrix_load_identity_doc}, + {"load_matrix", (PyCFunction)py_matrix_load_matrix, METH_O, py_matrix_load_matrix_doc}, {"load_projection_matrix", - (PyCFunction)bpygpu_matrix_load_projection_matrix, + (PyCFunction)py_matrix_load_projection_matrix, METH_O, - bpygpu_matrix_load_projection_matrix_doc}, + py_matrix_load_projection_matrix_doc}, /* Read State */ {"get_projection_matrix", - (PyCFunction)bpygpu_matrix_get_projection_matrix, + (PyCFunction)py_matrix_get_projection_matrix, METH_NOARGS, - bpygpu_matrix_get_projection_matrix_doc}, + py_matrix_get_projection_matrix_doc}, {"get_model_view_matrix", - (PyCFunction)bpygpu_matrix_get_model_view_matrix, + (PyCFunction)py_matrix_get_model_view_matrix, METH_NOARGS, - bpygpu_matrix_get_model_view_matrix_doc}, + py_matrix_get_model_view_matrix_doc}, {"get_normal_matrix", - (PyCFunction)bpygpu_matrix_get_normal_matrix, + (PyCFunction)py_matrix_get_normal_matrix, METH_NOARGS, - bpygpu_matrix_get_normal_matrix_doc}, + py_matrix_get_normal_matrix_doc}, {NULL, NULL, 0, NULL}, }; -PyDoc_STRVAR(bpygpu_matrix_doc, "This module provides access to the matrix stack."); +PyDoc_STRVAR(py_matrix_doc, "This module provides access to the matrix stack."); static PyModuleDef BPyGPU_matrix_module_def = { PyModuleDef_HEAD_INIT, .m_name = "gpu.matrix", - .m_doc = bpygpu_matrix_doc, - .m_methods = bpygpu_matrix_methods, + .m_doc = py_matrix_doc, + .m_methods = py_matrix_methods, }; PyObject *BPyInit_gpu_matrix(void) diff --git a/source/blender/python/gpu/gpu_py_offscreen.c b/source/blender/python/gpu/gpu_py_offscreen.c index 6d14dd0de5f..00d367c603b 100644 --- a/source/blender/python/gpu/gpu_py_offscreen.c +++ b/source/blender/python/gpu/gpu_py_offscreen.c @@ -58,9 +58,9 @@ /** \name GPUOffScreen Common Utilities * \{ */ -static int bpygpu_offscreen_valid_check(BPyGPUOffScreen *bpygpu_ofs) +static int py_offscreen_valid_check(BPyGPUOffScreen *py_ofs) { - if (UNLIKELY(bpygpu_ofs->ofs == NULL)) { + if (UNLIKELY(py_ofs->ofs == NULL)) { PyErr_SetString(PyExc_ReferenceError, "GPU offscreen was freed, no further access is valid"); return -1; } @@ -69,7 +69,7 @@ static int bpygpu_offscreen_valid_check(BPyGPUOffScreen *bpygpu_ofs) #define BPY_GPU_OFFSCREEN_CHECK_OBJ(bpygpu) \ { \ - if (UNLIKELY(bpygpu_offscreen_valid_check(bpygpu) == -1)) { \ + if (UNLIKELY(py_offscreen_valid_check(bpygpu) == -1)) { \ return NULL; \ } \ } \ @@ -81,7 +81,7 @@ static int bpygpu_offscreen_valid_check(BPyGPUOffScreen *bpygpu_ofs) /** \name GPUOffscreen Type * \{ */ -static PyObject *bpygpu_offscreen_new(PyTypeObject *UNUSED(self), PyObject *args, PyObject *kwds) +static PyObject *py_offscreen_new(PyTypeObject *UNUSED(self), PyObject *args, PyObject *kwds) { BPYGPU_IS_INIT_OR_ERROR_OBJ; @@ -112,23 +112,23 @@ static PyObject *bpygpu_offscreen_new(PyTypeObject *UNUSED(self), PyObject *args return BPyGPUOffScreen_CreatePyObject(ofs); } -PyDoc_STRVAR(bpygpu_offscreen_width_doc, "Width of the texture.\n\n:type: `int`"); -static PyObject *bpygpu_offscreen_width_get(BPyGPUOffScreen *self, void *UNUSED(type)) +PyDoc_STRVAR(py_offscreen_width_doc, "Width of the texture.\n\n:type: `int`"); +static PyObject *py_offscreen_width_get(BPyGPUOffScreen *self, void *UNUSED(type)) { BPY_GPU_OFFSCREEN_CHECK_OBJ(self); return PyLong_FromLong(GPU_offscreen_width(self->ofs)); } -PyDoc_STRVAR(bpygpu_offscreen_height_doc, "Height of the texture.\n\n:type: `int`"); -static PyObject *bpygpu_offscreen_height_get(BPyGPUOffScreen *self, void *UNUSED(type)) +PyDoc_STRVAR(py_offscreen_height_doc, "Height of the texture.\n\n:type: `int`"); +static PyObject *py_offscreen_height_get(BPyGPUOffScreen *self, void *UNUSED(type)) { BPY_GPU_OFFSCREEN_CHECK_OBJ(self); return PyLong_FromLong(GPU_offscreen_height(self->ofs)); } -PyDoc_STRVAR(bpygpu_offscreen_color_texture_doc, +PyDoc_STRVAR(py_offscreen_color_texture_doc, "OpenGL bindcode for the color texture.\n\n:type: `int`"); -static PyObject *bpygpu_offscreen_color_texture_get(BPyGPUOffScreen *self, void *UNUSED(type)) +static PyObject *py_offscreen_color_texture_get(BPyGPUOffScreen *self, void *UNUSED(type)) { BPY_GPU_OFFSCREEN_CHECK_OBJ(self); GPUTexture *texture = GPU_offscreen_color_texture(self->ofs); @@ -136,7 +136,7 @@ static PyObject *bpygpu_offscreen_color_texture_get(BPyGPUOffScreen *self, void } PyDoc_STRVAR( - bpygpu_offscreen_bind_doc, + py_offscreen_bind_doc, ".. method:: bind(save=True)\n" "\n" " Bind the offscreen object.\n" @@ -145,7 +145,7 @@ PyDoc_STRVAR( "\n" " :arg save: Save the current OpenGL state, so that it can be restored when unbinding.\n" " :type save: `bool`\n"); -static PyObject *bpygpu_offscreen_bind(BPyGPUOffScreen *self, PyObject *args, PyObject *kwds) +static PyObject *py_offscreen_bind(BPyGPUOffScreen *self, PyObject *args, PyObject *kwds) { BPY_GPU_OFFSCREEN_CHECK_OBJ(self); bool save = true; @@ -165,7 +165,7 @@ static PyObject *bpygpu_offscreen_bind(BPyGPUOffScreen *self, PyObject *args, Py return (PyObject *)self; } -PyDoc_STRVAR(bpygpu_offscreen_unbind_doc, +PyDoc_STRVAR(py_offscreen_unbind_doc, ".. method:: unbind(restore=True)\n" "\n" " Unbind the offscreen object.\n" @@ -173,7 +173,7 @@ PyDoc_STRVAR(bpygpu_offscreen_unbind_doc, " :arg restore: Restore the OpenGL state, can only be used when the state has been " "saved before.\n" " :type restore: `bool`\n"); -static PyObject *bpygpu_offscreen_unbind(BPyGPUOffScreen *self, PyObject *args, PyObject *kwds) +static PyObject *py_offscreen_unbind(BPyGPUOffScreen *self, PyObject *args, PyObject *kwds) { bool restore = true; @@ -191,7 +191,7 @@ static PyObject *bpygpu_offscreen_unbind(BPyGPUOffScreen *self, PyObject *args, } PyDoc_STRVAR( - bpygpu_offscreen_draw_view3d_doc, + py_offscreen_draw_view3d_doc, ".. method:: draw_view3d(scene, view_layer, view3d, region, view_matrix, projection_matrix)\n" "\n" " Draw the 3d viewport in the offscreen object.\n" @@ -208,9 +208,7 @@ PyDoc_STRVAR( " :type view_matrix: :class:`mathutils.Matrix`\n" " :arg projection_matrix: Projection Matrix (e.g. ``camera.calc_matrix_camera(...)``).\n" " :type projection_matrix: :class:`mathutils.Matrix`\n"); -static PyObject *bpygpu_offscreen_draw_view3d(BPyGPUOffScreen *self, - PyObject *args, - PyObject *kwds) +static PyObject *py_offscreen_draw_view3d(BPyGPUOffScreen *self, PyObject *args, PyObject *kwds) { MatrixObject *py_mat_view, *py_mat_projection; PyObject *py_scene, *py_view_layer, *py_region, *py_view3d; @@ -272,12 +270,12 @@ static PyObject *bpygpu_offscreen_draw_view3d(BPyGPUOffScreen *self, Py_RETURN_NONE; } -PyDoc_STRVAR(bpygpu_offscreen_free_doc, +PyDoc_STRVAR(py_offscreen_free_doc, ".. method:: free()\n" "\n" " Free the offscreen object.\n" " The framebuffer, texture and render objects will no longer be accessible.\n"); -static PyObject *bpygpu_offscreen_free(BPyGPUOffScreen *self) +static PyObject *py_offscreen_free(BPyGPUOffScreen *self) { BPY_GPU_OFFSCREEN_CHECK_OBJ(self); @@ -286,12 +284,12 @@ static PyObject *bpygpu_offscreen_free(BPyGPUOffScreen *self) Py_RETURN_NONE; } -static PyObject *bpygpu_offscreen_bind_context_enter(BPyGPUOffScreen *UNUSED(self)) +static PyObject *py_offscreen_bind_context_enter(BPyGPUOffScreen *UNUSED(self)) { Py_RETURN_NONE; } -static PyObject *bpygpu_offscreen_bind_context_exit(BPyGPUOffScreen *self, PyObject *UNUSED(args)) +static PyObject *py_offscreen_bind_context_exit(BPyGPUOffScreen *self, PyObject *UNUSED(args)) { GPU_offscreen_unbind(self->ofs, self->is_saved); Py_RETURN_NONE; @@ -305,41 +303,34 @@ static void BPyGPUOffScreen__tp_dealloc(BPyGPUOffScreen *self) Py_TYPE(self)->tp_free((PyObject *)self); } -static PyGetSetDef bpygpu_offscreen_getseters[] = { +static PyGetSetDef py_offscreen_getseters[] = { {"color_texture", - (getter)bpygpu_offscreen_color_texture_get, + (getter)py_offscreen_color_texture_get, (setter)NULL, - bpygpu_offscreen_color_texture_doc, - NULL}, - {"width", (getter)bpygpu_offscreen_width_get, (setter)NULL, bpygpu_offscreen_width_doc, NULL}, - {"height", - (getter)bpygpu_offscreen_height_get, - (setter)NULL, - bpygpu_offscreen_height_doc, + py_offscreen_color_texture_doc, NULL}, + {"width", (getter)py_offscreen_width_get, (setter)NULL, py_offscreen_width_doc, NULL}, + {"height", (getter)py_offscreen_height_get, (setter)NULL, py_offscreen_height_doc, NULL}, {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ }; -static struct PyMethodDef bpygpu_offscreen_methods[] = { - {"bind", - (PyCFunction)bpygpu_offscreen_bind, - METH_VARARGS | METH_KEYWORDS, - bpygpu_offscreen_bind_doc}, +static struct PyMethodDef py_offscreen_methods[] = { + {"bind", (PyCFunction)py_offscreen_bind, METH_VARARGS | METH_KEYWORDS, py_offscreen_bind_doc}, {"unbind", - (PyCFunction)bpygpu_offscreen_unbind, + (PyCFunction)py_offscreen_unbind, METH_VARARGS | METH_KEYWORDS, - bpygpu_offscreen_unbind_doc}, + py_offscreen_unbind_doc}, {"draw_view3d", - (PyCFunction)bpygpu_offscreen_draw_view3d, + (PyCFunction)py_offscreen_draw_view3d, METH_VARARGS | METH_KEYWORDS, - bpygpu_offscreen_draw_view3d_doc}, - {"free", (PyCFunction)bpygpu_offscreen_free, METH_NOARGS, bpygpu_offscreen_free_doc}, - {"__enter__", (PyCFunction)bpygpu_offscreen_bind_context_enter, METH_NOARGS}, - {"__exit__", (PyCFunction)bpygpu_offscreen_bind_context_exit, METH_VARARGS}, + py_offscreen_draw_view3d_doc}, + {"free", (PyCFunction)py_offscreen_free, METH_NOARGS, py_offscreen_free_doc}, + {"__enter__", (PyCFunction)py_offscreen_bind_context_enter, METH_NOARGS}, + {"__exit__", (PyCFunction)py_offscreen_bind_context_exit, METH_VARARGS}, {NULL, NULL, 0, NULL}, }; -PyDoc_STRVAR(bpygpu_offscreen_doc, +PyDoc_STRVAR(py_offscreen_doc, ".. class:: GPUOffScreen(width, height)\n" "\n" " This object gives access to off screen buffers.\n" @@ -353,10 +344,10 @@ PyTypeObject BPyGPUOffScreen_Type = { .tp_basicsize = sizeof(BPyGPUOffScreen), .tp_dealloc = (destructor)BPyGPUOffScreen__tp_dealloc, .tp_flags = Py_TPFLAGS_DEFAULT, - .tp_doc = bpygpu_offscreen_doc, - .tp_methods = bpygpu_offscreen_methods, - .tp_getset = bpygpu_offscreen_getseters, - .tp_new = bpygpu_offscreen_new, + .tp_doc = py_offscreen_doc, + .tp_methods = py_offscreen_methods, + .tp_getset = py_offscreen_getseters, + .tp_new = py_offscreen_new, }; /** \} */ diff --git a/source/blender/python/gpu/gpu_py_select.c b/source/blender/python/gpu/gpu_py_select.c index abe46301abb..4fa9d5ebc7a 100644 --- a/source/blender/python/gpu/gpu_py_select.c +++ b/source/blender/python/gpu/gpu_py_select.c @@ -40,14 +40,14 @@ /** \name Methods * \{ */ -PyDoc_STRVAR(bpygpu_select_load_id_doc, +PyDoc_STRVAR(py_select_load_id_doc, ".. function:: load_id(id)\n" "\n" " Set the selection ID.\n" "\n" " :param id: Number (32-bit uint).\n" " :type select: int\n"); -static PyObject *bpygpu_select_load_id(PyObject *UNUSED(self), PyObject *value) +static PyObject *py_select_load_id(PyObject *UNUSED(self), PyObject *value) { uint id; if ((id = PyC_Long_AsU32(value)) == (uint)-1) { @@ -62,18 +62,18 @@ static PyObject *bpygpu_select_load_id(PyObject *UNUSED(self), PyObject *value) /** \name Module * \{ */ -static struct PyMethodDef bpygpu_select_methods[] = { +static struct PyMethodDef py_select_methods[] = { /* Manage Stack */ - {"load_id", (PyCFunction)bpygpu_select_load_id, METH_O, bpygpu_select_load_id_doc}, + {"load_id", (PyCFunction)py_select_load_id, METH_O, py_select_load_id_doc}, {NULL, NULL, 0, NULL}, }; -PyDoc_STRVAR(bpygpu_select_doc, "This module provides access to selection."); +PyDoc_STRVAR(py_select_doc, "This module provides access to selection."); static PyModuleDef BPyGPU_select_module_def = { PyModuleDef_HEAD_INIT, .m_name = "gpu.select", - .m_doc = bpygpu_select_doc, - .m_methods = bpygpu_select_methods, + .m_doc = py_select_doc, + .m_methods = py_select_methods, }; PyObject *BPyInit_gpu_select(void) diff --git a/source/blender/python/gpu/gpu_py_shader.c b/source/blender/python/gpu/gpu_py_shader.c index c90a4a7bc9d..526b96f8584 100644 --- a/source/blender/python/gpu/gpu_py_shader.c +++ b/source/blender/python/gpu/gpu_py_shader.c @@ -39,45 +39,19 @@ /** \name Enum Conversion. * \{ */ -static int bpygpu_ParseBultinShaderEnum(PyObject *o, void *p) -{ - Py_ssize_t mode_id_len; - const char *mode_id = _PyUnicode_AsStringAndSize(o, &mode_id_len); - if (mode_id == NULL) { - PyErr_Format(PyExc_ValueError, "expected a string, got %s", Py_TYPE(o)->tp_name); - return 0; - } -#define MATCH_ID(id) \ - if (mode_id_len == (Py_ssize_t)strlen(STRINGIFY(id))) { \ - if (STREQ(mode_id, STRINGIFY(id))) { \ - mode = GPU_SHADER_##id; \ - goto success; \ - } \ - } \ - ((void)0) - - eGPUBuiltinShader mode; - MATCH_ID(2D_UNIFORM_COLOR); - MATCH_ID(2D_FLAT_COLOR); - MATCH_ID(2D_SMOOTH_COLOR); - MATCH_ID(2D_IMAGE); - MATCH_ID(3D_UNIFORM_COLOR); - MATCH_ID(3D_FLAT_COLOR); - MATCH_ID(3D_SMOOTH_COLOR); - MATCH_ID(3D_POLYLINE_UNIFORM_COLOR); - -#undef MATCH_ID - PyErr_Format(PyExc_ValueError, "unknown type literal: '%s'", mode_id); - return 0; - -success: - (*(eGPUBuiltinShader *)p) = mode; - return 1; -} +static const struct PyC_StringEnumItems pygpu_bultinshader_items[] = { + {GPU_SHADER_2D_UNIFORM_COLOR, "2D_UNIFORM_COLOR"}, + {GPU_SHADER_2D_FLAT_COLOR, "2D_FLAT_COLOR"}, + {GPU_SHADER_2D_SMOOTH_COLOR, "2D_SMOOTH_COLOR"}, + {GPU_SHADER_2D_IMAGE, "2D_IMAGE"}, + {GPU_SHADER_3D_UNIFORM_COLOR, "3D_UNIFORM_COLOR"}, + {GPU_SHADER_3D_FLAT_COLOR, "3D_FLAT_COLOR"}, + {GPU_SHADER_3D_SMOOTH_COLOR, "3D_SMOOTH_COLOR"}, + {GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR, "3D_POLYLINE_UNIFORM_COLOR"}, + {0, NULL}, +}; -static int bpygpu_uniform_location_get(GPUShader *shader, - const char *name, - const char *error_prefix) +static int py_uniform_location_get(GPUShader *shader, const char *name, const char *error_prefix) { const int uniform = GPU_shader_get_uniform(shader, name); @@ -94,7 +68,7 @@ static int bpygpu_uniform_location_get(GPUShader *shader, /** \name Shader Type * \{ */ -static PyObject *bpygpu_shader_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds) +static PyObject *py_shader_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds) { BPYGPU_IS_INIT_OR_ERROR_OBJ; @@ -133,17 +107,17 @@ static PyObject *bpygpu_shader_new(PyTypeObject *UNUSED(type), PyObject *args, P } PyDoc_STRVAR( - bpygpu_shader_bind_doc, + py_shader_bind_doc, ".. method:: bind()\n" "\n" " Bind the shader object. Required to be able to change uniforms of this shader.\n"); -static PyObject *bpygpu_shader_bind(BPyGPUShader *self) +static PyObject *py_shader_bind(BPyGPUShader *self) { GPU_shader_bind(self->shader); Py_RETURN_NONE; } -PyDoc_STRVAR(bpygpu_shader_uniform_from_name_doc, +PyDoc_STRVAR(py_shader_uniform_from_name_doc, ".. method:: uniform_from_name(name)\n" "\n" " Get uniform location by name.\n" @@ -152,14 +126,14 @@ PyDoc_STRVAR(bpygpu_shader_uniform_from_name_doc, " :type name: `str`\n" " :return: Location of the uniform variable.\n" " :rtype: `int`\n"); -static PyObject *bpygpu_shader_uniform_from_name(BPyGPUShader *self, PyObject *arg) +static PyObject *py_shader_uniform_from_name(BPyGPUShader *self, PyObject *arg) { const char *name = PyUnicode_AsUTF8(arg); if (name == NULL) { return NULL; } - const int uniform = bpygpu_uniform_location_get(self->shader, name, "GPUShader.get_uniform"); + const int uniform = py_uniform_location_get(self->shader, name, "GPUShader.get_uniform"); if (uniform == -1) { return NULL; @@ -169,7 +143,7 @@ static PyObject *bpygpu_shader_uniform_from_name(BPyGPUShader *self, PyObject *a } PyDoc_STRVAR( - bpygpu_shader_uniform_block_from_name_doc, + py_shader_uniform_block_from_name_doc, ".. method:: uniform_block_from_name(name)\n" "\n" " Get uniform block location by name.\n" @@ -178,7 +152,7 @@ PyDoc_STRVAR( " :type name: `str`\n" " :return: The location of the uniform block variable.\n" " :rtype: `int`\n"); -static PyObject *bpygpu_shader_uniform_block_from_name(BPyGPUShader *self, PyObject *arg) +static PyObject *py_shader_uniform_block_from_name(BPyGPUShader *self, PyObject *arg) { const char *name = PyUnicode_AsUTF8(arg); if (name == NULL) { @@ -195,12 +169,12 @@ static PyObject *bpygpu_shader_uniform_block_from_name(BPyGPUShader *self, PyObj return PyLong_FromLong(uniform); } -static bool bpygpu_shader_uniform_vector_imp(PyObject *args, - int elem_size, - int *r_location, - int *r_length, - int *r_count, - Py_buffer *r_pybuffer) +static bool py_shader_uniform_vector_imp(PyObject *args, + int elem_size, + int *r_location, + int *r_length, + int *r_count, + Py_buffer *r_pybuffer) { PyObject *buffer; @@ -223,7 +197,7 @@ static bool bpygpu_shader_uniform_vector_imp(PyObject *args, return true; } -PyDoc_STRVAR(bpygpu_shader_uniform_vector_float_doc, +PyDoc_STRVAR(py_shader_uniform_vector_float_doc, ".. method:: uniform_vector_float(location, buffer, length, count)\n" "\n" " Set the buffer to fill the uniform.\n" @@ -243,14 +217,13 @@ PyDoc_STRVAR(bpygpu_shader_uniform_vector_float_doc, " :param count: Specifies the number of elements, vector or matrices that are to " "be modified.\n" " :type count: int\n"); -static PyObject *bpygpu_shader_uniform_vector_float(BPyGPUShader *self, PyObject *args) +static PyObject *py_shader_uniform_vector_float(BPyGPUShader *self, PyObject *args) { int location, length, count; Py_buffer pybuffer; - if (!bpygpu_shader_uniform_vector_imp( - args, sizeof(float), &location, &length, &count, &pybuffer)) { + if (!py_shader_uniform_vector_imp(args, sizeof(float), &location, &length, &count, &pybuffer)) { return NULL; } @@ -261,18 +234,17 @@ static PyObject *bpygpu_shader_uniform_vector_float(BPyGPUShader *self, PyObject Py_RETURN_NONE; } -PyDoc_STRVAR(bpygpu_shader_uniform_vector_int_doc, +PyDoc_STRVAR(py_shader_uniform_vector_int_doc, ".. method:: uniform_vector_int(location, buffer, length, count)\n" "\n" " See GPUShader.uniform_vector_float(...) description.\n"); -static PyObject *bpygpu_shader_uniform_vector_int(BPyGPUShader *self, PyObject *args) +static PyObject *py_shader_uniform_vector_int(BPyGPUShader *self, PyObject *args) { int location, length, count; Py_buffer pybuffer; - if (!bpygpu_shader_uniform_vector_imp( - args, sizeof(int), &location, &length, &count, &pybuffer)) { + if (!py_shader_uniform_vector_imp(args, sizeof(int), &location, &length, &count, &pybuffer)) { return NULL; } @@ -283,7 +255,7 @@ static PyObject *bpygpu_shader_uniform_vector_int(BPyGPUShader *self, PyObject * Py_RETURN_NONE; } -PyDoc_STRVAR(bpygpu_shader_uniform_bool_doc, +PyDoc_STRVAR(py_shader_uniform_bool_doc, ".. method:: uniform_bool(name, seq)\n" "\n" " Specify the value of a uniform variable for the current program object.\n" @@ -292,7 +264,7 @@ PyDoc_STRVAR(bpygpu_shader_uniform_bool_doc, " :type name: str\n" " :param seq: Value that will be used to update the specified uniform variable.\n" " :type seq: sequence of bools\n"); -static PyObject *bpygpu_shader_uniform_bool(BPyGPUShader *self, PyObject *args) +static PyObject *py_shader_uniform_bool(BPyGPUShader *self, PyObject *args) { const char *error_prefix = "GPUShader.uniform_bool"; @@ -336,7 +308,7 @@ static PyObject *bpygpu_shader_uniform_bool(BPyGPUShader *self, PyObject *args) return NULL; } - const int location = bpygpu_uniform_location_get(self->shader, params.id, error_prefix); + const int location = py_uniform_location_get(self->shader, params.id, error_prefix); if (location == -1) { return NULL; @@ -347,7 +319,7 @@ static PyObject *bpygpu_shader_uniform_bool(BPyGPUShader *self, PyObject *args) Py_RETURN_NONE; } -PyDoc_STRVAR(bpygpu_shader_uniform_float_doc, +PyDoc_STRVAR(py_shader_uniform_float_doc, ".. method:: uniform_float(name, value)\n" "\n" " Specify the value of a uniform variable for the current program object.\n" @@ -356,7 +328,7 @@ PyDoc_STRVAR(bpygpu_shader_uniform_float_doc, " :type name: str\n" " :param value: Value that will be used to update the specified uniform variable.\n" " :type value: single number or sequence of numbers\n"); -static PyObject *bpygpu_shader_uniform_float(BPyGPUShader *self, PyObject *args) +static PyObject *py_shader_uniform_float(BPyGPUShader *self, PyObject *args) { const char *error_prefix = "GPUShader.uniform_float"; @@ -405,7 +377,7 @@ static PyObject *bpygpu_shader_uniform_float(BPyGPUShader *self, PyObject *args) return NULL; } - const int location = bpygpu_uniform_location_get(self->shader, params.id, error_prefix); + const int location = py_uniform_location_get(self->shader, params.id, error_prefix); if (location == -1) { return NULL; @@ -416,7 +388,7 @@ static PyObject *bpygpu_shader_uniform_float(BPyGPUShader *self, PyObject *args) Py_RETURN_NONE; } -PyDoc_STRVAR(bpygpu_shader_uniform_int_doc, +PyDoc_STRVAR(py_shader_uniform_int_doc, ".. method:: uniform_int(name, seq)\n" "\n" " Specify the value of a uniform variable for the current program object.\n" @@ -425,7 +397,7 @@ PyDoc_STRVAR(bpygpu_shader_uniform_int_doc, " :type name: str\n" " :param seq: Value that will be used to update the specified uniform variable.\n" " :type seq: sequence of numbers\n"); -static PyObject *bpygpu_shader_uniform_int(BPyGPUShader *self, PyObject *args) +static PyObject *py_shader_uniform_int(BPyGPUShader *self, PyObject *args) { const char *error_prefix = "GPUShader.uniform_int"; @@ -475,7 +447,7 @@ static PyObject *bpygpu_shader_uniform_int(BPyGPUShader *self, PyObject *args) return NULL; } - const int location = bpygpu_uniform_location_get(self->shader, params.id, error_prefix); + const int location = py_uniform_location_get(self->shader, params.id, error_prefix); if (location == -1) { return NULL; @@ -487,7 +459,7 @@ static PyObject *bpygpu_shader_uniform_int(BPyGPUShader *self, PyObject *args) } PyDoc_STRVAR( - bpygpu_shader_attr_from_name_doc, + py_shader_attr_from_name_doc, ".. method:: attr_from_name(name)\n" "\n" " Get attribute location by name.\n" @@ -496,7 +468,7 @@ PyDoc_STRVAR( " :type name: str\n" " :return: The location of an attribute variable.\n" " :rtype: int\n"); -static PyObject *bpygpu_shader_attr_from_name(BPyGPUShader *self, PyObject *arg) +static PyObject *py_shader_attr_from_name(BPyGPUShader *self, PyObject *arg) { const char *name = PyUnicode_AsUTF8(arg); if (name == NULL) { @@ -513,75 +485,69 @@ static PyObject *bpygpu_shader_attr_from_name(BPyGPUShader *self, PyObject *arg) return PyLong_FromLong(attr); } -PyDoc_STRVAR(bpygpu_shader_calc_format_doc, +PyDoc_STRVAR(py_shader_calc_format_doc, ".. method:: calc_format()\n" "\n" " Build a new format based on the attributes of the shader.\n" "\n" " :return: vertex attribute format for the shader\n" " :rtype: GPUVertFormat\n"); -static PyObject *bpygpu_shader_calc_format(BPyGPUShader *self, PyObject *UNUSED(arg)) +static PyObject *py_shader_calc_format(BPyGPUShader *self, PyObject *UNUSED(arg)) { BPyGPUVertFormat *ret = (BPyGPUVertFormat *)BPyGPUVertFormat_CreatePyObject(NULL); GPU_vertformat_from_shader(&ret->fmt, self->shader); return (PyObject *)ret; } -static struct PyMethodDef bpygpu_shader_methods[] = { - {"bind", (PyCFunction)bpygpu_shader_bind, METH_NOARGS, bpygpu_shader_bind_doc}, +static struct PyMethodDef py_shader_methods[] = { + {"bind", (PyCFunction)py_shader_bind, METH_NOARGS, py_shader_bind_doc}, {"uniform_from_name", - (PyCFunction)bpygpu_shader_uniform_from_name, + (PyCFunction)py_shader_uniform_from_name, METH_O, - bpygpu_shader_uniform_from_name_doc}, + py_shader_uniform_from_name_doc}, {"uniform_block_from_name", - (PyCFunction)bpygpu_shader_uniform_block_from_name, + (PyCFunction)py_shader_uniform_block_from_name, METH_O, - bpygpu_shader_uniform_block_from_name_doc}, + py_shader_uniform_block_from_name_doc}, {"uniform_vector_float", - (PyCFunction)bpygpu_shader_uniform_vector_float, + (PyCFunction)py_shader_uniform_vector_float, METH_VARARGS, - bpygpu_shader_uniform_vector_float_doc}, + py_shader_uniform_vector_float_doc}, {"uniform_vector_int", - (PyCFunction)bpygpu_shader_uniform_vector_int, + (PyCFunction)py_shader_uniform_vector_int, METH_VARARGS, - bpygpu_shader_uniform_vector_int_doc}, + py_shader_uniform_vector_int_doc}, {"uniform_bool", - (PyCFunction)bpygpu_shader_uniform_bool, + (PyCFunction)py_shader_uniform_bool, METH_VARARGS, - bpygpu_shader_uniform_bool_doc}, + py_shader_uniform_bool_doc}, {"uniform_float", - (PyCFunction)bpygpu_shader_uniform_float, - METH_VARARGS, - bpygpu_shader_uniform_float_doc}, - {"uniform_int", - (PyCFunction)bpygpu_shader_uniform_int, + (PyCFunction)py_shader_uniform_float, METH_VARARGS, - bpygpu_shader_uniform_int_doc}, + py_shader_uniform_float_doc}, + {"uniform_int", (PyCFunction)py_shader_uniform_int, METH_VARARGS, py_shader_uniform_int_doc}, {"attr_from_name", - (PyCFunction)bpygpu_shader_attr_from_name, + (PyCFunction)py_shader_attr_from_name, METH_O, - bpygpu_shader_attr_from_name_doc}, - {"format_calc", - (PyCFunction)bpygpu_shader_calc_format, - METH_NOARGS, - bpygpu_shader_calc_format_doc}, + py_shader_attr_from_name_doc}, + {"format_calc", (PyCFunction)py_shader_calc_format, METH_NOARGS, py_shader_calc_format_doc}, {NULL, NULL, 0, NULL}, }; PyDoc_STRVAR( - bpygpu_shader_program_doc, + py_shader_program_doc, "The name of the program object for use by the OpenGL API (read-only).\n\n:type: int"); -static PyObject *bpygpu_shader_program_get(BPyGPUShader *self, void *UNUSED(closure)) +static PyObject *py_shader_program_get(BPyGPUShader *self, void *UNUSED(closure)) { return PyLong_FromLong(GPU_shader_get_program(self->shader)); } -static PyGetSetDef bpygpu_shader_getseters[] = { - {"program", (getter)bpygpu_shader_program_get, (setter)NULL, bpygpu_shader_program_doc, NULL}, +static PyGetSetDef py_shader_getseters[] = { + {"program", (getter)py_shader_program_get, (setter)NULL, py_shader_program_doc, NULL}, {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ }; -static void bpygpu_shader_dealloc(BPyGPUShader *self) +static void py_shader_dealloc(BPyGPUShader *self) { if (self->is_builtin == false) { GPU_shader_free(self->shader); @@ -590,7 +556,7 @@ static void bpygpu_shader_dealloc(BPyGPUShader *self) } PyDoc_STRVAR( - bpygpu_shader_doc, + py_shader_doc, ".. class:: GPUShader(vertexcode, fragcode, geocode=None, libcode=None, defines=None)\n" "\n" " GPUShader combines multiple GLSL shaders into a program used for drawing.\n" @@ -624,12 +590,12 @@ PyDoc_STRVAR( PyTypeObject BPyGPUShader_Type = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "GPUShader", .tp_basicsize = sizeof(BPyGPUShader), - .tp_dealloc = (destructor)bpygpu_shader_dealloc, + .tp_dealloc = (destructor)py_shader_dealloc, .tp_flags = Py_TPFLAGS_DEFAULT, - .tp_doc = bpygpu_shader_doc, - .tp_methods = bpygpu_shader_methods, - .tp_getset = bpygpu_shader_getseters, - .tp_new = bpygpu_shader_new, + .tp_doc = py_shader_doc, + .tp_methods = py_shader_methods, + .tp_getset = py_shader_getseters, + .tp_new = py_shader_new, }; /** \} */ @@ -638,17 +604,17 @@ PyTypeObject BPyGPUShader_Type = { /** \name gpu.shader Module API * \{ */ -PyDoc_STRVAR(bpygpu_shader_unbind_doc, +PyDoc_STRVAR(py_shader_unbind_doc, ".. function:: unbind()\n" "\n" " Unbind the bound shader object.\n"); -static PyObject *bpygpu_shader_unbind(BPyGPUShader *UNUSED(self)) +static PyObject *py_shader_unbind(BPyGPUShader *UNUSED(self)) { GPU_shader_unbind(); Py_RETURN_NONE; } -PyDoc_STRVAR(bpygpu_shader_from_builtin_doc, +PyDoc_STRVAR(py_shader_from_builtin_doc, ".. function:: from_builtin(shader_name)\n" "\n" " Shaders that are embedded in the blender internal code.\n" @@ -668,22 +634,21 @@ PyDoc_STRVAR(bpygpu_shader_from_builtin_doc, " :type shader_name: str\n" " :return: Shader object corresponding to the given name.\n" " :rtype: :class:`bpy.types.GPUShader`\n"); -static PyObject *bpygpu_shader_from_builtin(PyObject *UNUSED(self), PyObject *arg) +static PyObject *py_shader_from_builtin(PyObject *UNUSED(self), PyObject *arg) { BPYGPU_IS_INIT_OR_ERROR_OBJ; - eGPUBuiltinShader shader_id; - - if (!bpygpu_ParseBultinShaderEnum(arg, &shader_id)) { + struct PyC_StringEnum pygpu_bultinshader = {pygpu_bultinshader_items}; + if (!PyC_ParseStringEnum(arg, &pygpu_bultinshader)) { return NULL; } - GPUShader *shader = GPU_shader_get_builtin_shader(shader_id); + GPUShader *shader = GPU_shader_get_builtin_shader(pygpu_bultinshader.value_found); return BPyGPUShader_CreatePyObject(shader, true); } -PyDoc_STRVAR(bpygpu_shader_code_from_builtin_doc, +PyDoc_STRVAR(py_shader_code_from_builtin_doc, ".. function:: code_from_builtin(shader_name)\n" "\n" " Exposes the internal shader code for query.\n" @@ -699,10 +664,8 @@ PyDoc_STRVAR(bpygpu_shader_code_from_builtin_doc, " :type shader_name: str\n" " :return: Vertex, fragment and geometry shader codes.\n" " :rtype: dict\n"); -static PyObject *bpygpu_shader_code_from_builtin(BPyGPUShader *UNUSED(self), PyObject *arg) +static PyObject *py_shader_code_from_builtin(BPyGPUShader *UNUSED(self), PyObject *arg) { - eGPUBuiltinShader shader_id; - const char *vert; const char *frag; const char *geom; @@ -710,11 +673,13 @@ static PyObject *bpygpu_shader_code_from_builtin(BPyGPUShader *UNUSED(self), PyO PyObject *item, *r_dict; - if (!bpygpu_ParseBultinShaderEnum(arg, &shader_id)) { + struct PyC_StringEnum pygpu_bultinshader = {pygpu_bultinshader_items}; + if (!PyC_ParseStringEnum(arg, &pygpu_bultinshader)) { return NULL; } - GPU_shader_get_builtin_shader_code(shader_id, &vert, &frag, &geom, &defines); + GPU_shader_get_builtin_shader_code( + pygpu_bultinshader.value_found, &vert, &frag, &geom, &defines); r_dict = PyDict_New(); @@ -735,20 +700,17 @@ static PyObject *bpygpu_shader_code_from_builtin(BPyGPUShader *UNUSED(self), PyO return r_dict; } -static struct PyMethodDef bpygpu_shader_module_methods[] = { - {"unbind", (PyCFunction)bpygpu_shader_unbind, METH_NOARGS, bpygpu_shader_unbind_doc}, - {"from_builtin", - (PyCFunction)bpygpu_shader_from_builtin, - METH_O, - bpygpu_shader_from_builtin_doc}, +static struct PyMethodDef py_shader_module_methods[] = { + {"unbind", (PyCFunction)py_shader_unbind, METH_NOARGS, py_shader_unbind_doc}, + {"from_builtin", (PyCFunction)py_shader_from_builtin, METH_O, py_shader_from_builtin_doc}, {"code_from_builtin", - (PyCFunction)bpygpu_shader_code_from_builtin, + (PyCFunction)py_shader_code_from_builtin, METH_O, - bpygpu_shader_code_from_builtin_doc}, + py_shader_code_from_builtin_doc}, {NULL, NULL, 0, NULL}, }; -PyDoc_STRVAR(bpygpu_shader_module_doc, +PyDoc_STRVAR(py_shader_module_doc, "This module provides access to GPUShader internal functions.\n" "\n" ".. rubric:: Built-in shaders\n" @@ -780,8 +742,8 @@ PyDoc_STRVAR(bpygpu_shader_module_doc, static PyModuleDef BPyGPU_shader_module_def = { PyModuleDef_HEAD_INIT, .m_name = "gpu.shader", - .m_doc = bpygpu_shader_module_doc, - .m_methods = bpygpu_shader_module_methods, + .m_doc = py_shader_module_doc, + .m_methods = py_shader_module_methods, }; /** \} */ diff --git a/source/blender/python/gpu/gpu_py_vertex_buffer.c b/source/blender/python/gpu/gpu_py_vertex_buffer.c index d8c6e67816a..8e19eac76d0 100644 --- a/source/blender/python/gpu/gpu_py_vertex_buffer.c +++ b/source/blender/python/gpu/gpu_py_vertex_buffer.c @@ -116,10 +116,10 @@ static void fill_format_sequence(void *data_dst_void, #undef WARN_TYPE_LIMIT_PUSH #undef WARN_TYPE_LIMIT_POP -static bool bpygpu_vertbuf_fill_impl(GPUVertBuf *vbo, - uint data_id, - PyObject *seq, - const char *error_prefix) +static bool py_vertbuf_fill_impl(GPUVertBuf *vbo, + uint data_id, + PyObject *seq, + const char *error_prefix) { const char *exc_str_size_mismatch = "Expected a %s of size %d, got %u"; @@ -213,10 +213,7 @@ static bool bpygpu_vertbuf_fill_impl(GPUVertBuf *vbo, return ok; } -static int bpygpu_attr_fill(GPUVertBuf *buf, - int id, - PyObject *py_seq_data, - const char *error_prefix) +static int py_attr_fill(GPUVertBuf *buf, int id, PyObject *py_seq_data, const char *error_prefix) { if (id < 0 || id >= GPU_vertbuf_get_format(buf)->attr_len) { PyErr_Format(PyExc_ValueError, "Format id %d out of range", id); @@ -228,7 +225,7 @@ static int bpygpu_attr_fill(GPUVertBuf *buf, return 0; } - if (!bpygpu_vertbuf_fill_impl(buf, (uint)id, py_seq_data, error_prefix)) { + if (!py_vertbuf_fill_impl(buf, (uint)id, py_seq_data, error_prefix)) { return 0; } @@ -241,7 +238,7 @@ static int bpygpu_attr_fill(GPUVertBuf *buf, /** \name VertBuf Type * \{ */ -static PyObject *bpygpu_VertBuf_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds) +static PyObject *py_VertBuf_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds) { struct { PyObject *py_fmt; @@ -263,7 +260,7 @@ static PyObject *bpygpu_VertBuf_new(PyTypeObject *UNUSED(type), PyObject *args, return BPyGPUVertBuf_CreatePyObject(vbo); } -PyDoc_STRVAR(bpygpu_VertBuf_attr_fill_doc, +PyDoc_STRVAR(py_VertBuf_attr_fill_doc, ".. method:: attr_fill(id, data)\n" "\n" " Insert data into the buffer for a single attribute.\n" @@ -272,7 +269,7 @@ PyDoc_STRVAR(bpygpu_VertBuf_attr_fill_doc, " :type id: int or str\n" " :param data: Sequence of data that should be stored in the buffer\n" " :type data: sequence of values or tuples\n"); -static PyObject *bpygpu_VertBuf_attr_fill(BPyGPUVertBuf *self, PyObject *args, PyObject *kwds) +static PyObject *py_VertBuf_attr_fill(BPyGPUVertBuf *self, PyObject *args, PyObject *kwds) { PyObject *data; PyObject *identifier; @@ -302,22 +299,22 @@ static PyObject *bpygpu_VertBuf_attr_fill(BPyGPUVertBuf *self, PyObject *args, P return NULL; } - if (!bpygpu_attr_fill(self->buf, id, data, "GPUVertBuf.attr_fill")) { + if (!py_attr_fill(self->buf, id, data, "GPUVertBuf.attr_fill")) { return NULL; } Py_RETURN_NONE; } -static struct PyMethodDef bpygpu_VertBuf_methods[] = { +static struct PyMethodDef py_VertBuf_methods[] = { {"attr_fill", - (PyCFunction)bpygpu_VertBuf_attr_fill, + (PyCFunction)py_VertBuf_attr_fill, METH_VARARGS | METH_KEYWORDS, - bpygpu_VertBuf_attr_fill_doc}, + py_VertBuf_attr_fill_doc}, {NULL, NULL, 0, NULL}, }; -static void bpygpu_VertBuf_dealloc(BPyGPUVertBuf *self) +static void py_VertBuf_dealloc(BPyGPUVertBuf *self) { GPU_vertbuf_discard(self->buf); Py_TYPE(self)->tp_free(self); @@ -335,11 +332,11 @@ PyDoc_STRVAR(py_gpu_vertex_buffer_doc, PyTypeObject BPyGPUVertBuf_Type = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "GPUVertBuf", .tp_basicsize = sizeof(BPyGPUVertBuf), - .tp_dealloc = (destructor)bpygpu_VertBuf_dealloc, + .tp_dealloc = (destructor)py_VertBuf_dealloc, .tp_flags = Py_TPFLAGS_DEFAULT, .tp_doc = py_gpu_vertex_buffer_doc, - .tp_methods = bpygpu_VertBuf_methods, - .tp_new = bpygpu_VertBuf_new, + .tp_methods = py_VertBuf_methods, + .tp_new = py_VertBuf_new, }; /** \} */ diff --git a/source/blender/python/gpu/gpu_py_vertex_format.c b/source/blender/python/gpu/gpu_py_vertex_format.c index 2d45eadcfe3..7d1e4ee4868 100644 --- a/source/blender/python/gpu/gpu_py_vertex_format.c +++ b/source/blender/python/gpu/gpu_py_vertex_format.c @@ -50,7 +50,7 @@ * Use with PyArg_ParseTuple's "O&" formatting. * \{ */ -static int bpygpu_parse_component_type(const char *str, int length) +static int py_parse_component_type(const char *str, int length) { if (length == 2) { switch (*((ushort *)str)) { @@ -83,7 +83,7 @@ static int bpygpu_parse_component_type(const char *str, int length) return -1; } -static int bpygpu_parse_fetch_mode(const char *str, int length) +static int py_parse_fetch_mode(const char *str, int length) { #define MATCH_ID(id) \ if (length == strlen(STRINGIFY(id))) { \ @@ -102,7 +102,7 @@ static int bpygpu_parse_fetch_mode(const char *str, int length) return -1; } -static int bpygpu_ParseVertCompType(PyObject *o, void *p) +static int py_ParseVertCompType(PyObject *o, void *p) { Py_ssize_t length; const char *str = _PyUnicode_AsStringAndSize(o, &length); @@ -112,7 +112,7 @@ static int bpygpu_ParseVertCompType(PyObject *o, void *p) return 0; } - const int comp_type = bpygpu_parse_component_type(str, length); + const int comp_type = py_parse_component_type(str, length); if (comp_type == -1) { PyErr_Format(PyExc_ValueError, "unknown component type: '%s", str); return 0; @@ -122,7 +122,7 @@ static int bpygpu_ParseVertCompType(PyObject *o, void *p) return 1; } -static int bpygpu_ParseVertFetchMode(PyObject *o, void *p) +static int py_ParseVertFetchMode(PyObject *o, void *p) { Py_ssize_t length; const char *str = _PyUnicode_AsStringAndSize(o, &length); @@ -132,7 +132,7 @@ static int bpygpu_ParseVertFetchMode(PyObject *o, void *p) return 0; } - const int fetch_mode = bpygpu_parse_fetch_mode(str, length); + const int fetch_mode = py_parse_fetch_mode(str, length); if (fetch_mode == -1) { PyErr_Format(PyExc_ValueError, "unknown type literal: '%s'", str); return 0; @@ -148,7 +148,7 @@ static int bpygpu_ParseVertFetchMode(PyObject *o, void *p) /** \name VertFormat Type * \{ */ -static PyObject *bpygpu_VertFormat_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds) +static PyObject *py_VertFormat_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds) { if (PyTuple_GET_SIZE(args) || (kwds && PyDict_Size(kwds))) { PyErr_SetString(PyExc_ValueError, "This function takes no arguments"); @@ -158,7 +158,7 @@ static PyObject *bpygpu_VertFormat_new(PyTypeObject *UNUSED(type), PyObject *arg } PyDoc_STRVAR( - bpygpu_VertFormat_attr_add_doc, + py_VertFormat_attr_add_doc, ".. method:: attr_add(id, comp_type, len, fetch_mode)\n" "\n" " Add a new attribute to the format.\n" @@ -177,7 +177,7 @@ PyDoc_STRVAR( " converted to a normal 4 byte float when used.\n" " Possible values are `FLOAT`, `INT`, `INT_TO_FLOAT_UNIT` and `INT_TO_FLOAT`.\n" " :type fetch_mode: `str`\n"); -static PyObject *bpygpu_VertFormat_attr_add(BPyGPUVertFormat *self, PyObject *args, PyObject *kwds) +static PyObject *py_VertFormat_attr_add(BPyGPUVertFormat *self, PyObject *args, PyObject *kwds) { struct { const char *id; @@ -197,10 +197,10 @@ static PyObject *bpygpu_VertFormat_attr_add(BPyGPUVertFormat *self, PyObject *ar kwds, &_parser, ¶ms.id, - bpygpu_ParseVertCompType, + py_ParseVertCompType, ¶ms.comp_type, ¶ms.len, - bpygpu_ParseVertFetchMode, + py_ParseVertFetchMode, ¶ms.fetch_mode)) { return NULL; } @@ -210,31 +210,31 @@ static PyObject *bpygpu_VertFormat_attr_add(BPyGPUVertFormat *self, PyObject *ar return PyLong_FromLong(attr_id); } -static struct PyMethodDef bpygpu_VertFormat_methods[] = { +static struct PyMethodDef py_VertFormat_methods[] = { {"attr_add", - (PyCFunction)bpygpu_VertFormat_attr_add, + (PyCFunction)py_VertFormat_attr_add, METH_VARARGS | METH_KEYWORDS, - bpygpu_VertFormat_attr_add_doc}, + py_VertFormat_attr_add_doc}, {NULL, NULL, 0, NULL}, }; -static void bpygpu_VertFormat_dealloc(BPyGPUVertFormat *self) +static void py_VertFormat_dealloc(BPyGPUVertFormat *self) { Py_TYPE(self)->tp_free(self); } -PyDoc_STRVAR(bpygpu_VertFormat_doc, +PyDoc_STRVAR(py_VertFormat_doc, ".. class:: GPUVertFormat()\n" "\n" " This object contains information about the structure of a vertex buffer.\n"); PyTypeObject BPyGPUVertFormat_Type = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "GPUVertFormat", .tp_basicsize = sizeof(BPyGPUVertFormat), - .tp_dealloc = (destructor)bpygpu_VertFormat_dealloc, + .tp_dealloc = (destructor)py_VertFormat_dealloc, .tp_flags = Py_TPFLAGS_DEFAULT, - .tp_doc = bpygpu_VertFormat_doc, - .tp_methods = bpygpu_VertFormat_methods, - .tp_new = bpygpu_VertFormat_new, + .tp_doc = py_VertFormat_doc, + .tp_methods = py_VertFormat_methods, + .tp_new = py_VertFormat_new, }; /** \} */ diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt index 772b31fd9d8..5d8330e368d 100644 --- a/source/blender/python/intern/CMakeLists.txt +++ b/source/blender/python/intern/CMakeLists.txt @@ -255,7 +255,11 @@ if(WITH_SDL) list(APPEND INC_SYS ${SDL_INCLUDE_DIR} ) - if(NOT WITH_SDL_DYNLOAD) + if(WITH_SDL_DYNLOAD) + list(APPEND LIB + extern_sdlew + ) + else() list(APPEND LIB ${SDL_LIBRARY} ) diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c index 804a28d0ebc..6462f8320d7 100644 --- a/source/blender/python/intern/bpy.c +++ b/source/blender/python/intern/bpy.c @@ -260,25 +260,19 @@ PyDoc_STRVAR(bpy_escape_identifier_doc, " :rtype: string\n"); static PyObject *bpy_escape_identifier(PyObject *UNUSED(self), PyObject *value) { - const char *value_str; Py_ssize_t value_str_len; - - char *value_escape_str; - Py_ssize_t value_escape_str_len; - PyObject *value_escape; - size_t size; - - value_str = _PyUnicode_AsStringAndSize(value, &value_str_len); + const char *value_str = _PyUnicode_AsStringAndSize(value, &value_str_len); if (value_str == NULL) { PyErr_SetString(PyExc_TypeError, "expected a string"); return NULL; } - size = (value_str_len * 2) + 1; - value_escape_str = PyMem_MALLOC(size); - value_escape_str_len = BLI_strescape(value_escape_str, value_str, size); + const size_t size = (value_str_len * 2) + 1; + char *value_escape_str = PyMem_MALLOC(size); + const Py_ssize_t value_escape_str_len = BLI_str_escape(value_escape_str, value_str, size); + PyObject *value_escape; if (value_escape_str_len == value_str_len) { Py_INCREF(value); value_escape = value; @@ -292,6 +286,44 @@ static PyObject *bpy_escape_identifier(PyObject *UNUSED(self), PyObject *value) return value_escape; } +PyDoc_STRVAR(bpy_unescape_identifier_doc, + ".. function:: unescape_identifier(string)\n" + "\n" + " Simple string un-escape function used for animation paths.\n" + " This performs the reverse of `escape_identifier`.\n" + "\n" + " :arg string: text\n" + " :type string: string\n" + " :return: The un-escaped string.\n" + " :rtype: string\n"); +static PyObject *bpy_unescape_identifier(PyObject *UNUSED(self), PyObject *value) +{ + Py_ssize_t value_str_len; + const char *value_str = _PyUnicode_AsStringAndSize(value, &value_str_len); + + if (value_str == NULL) { + PyErr_SetString(PyExc_TypeError, "expected a string"); + return NULL; + } + + const size_t size = value_str_len + 1; + char *value_unescape_str = PyMem_MALLOC(size); + const Py_ssize_t value_unescape_str_len = BLI_str_unescape(value_unescape_str, value_str, size); + + PyObject *value_unescape; + if (value_unescape_str_len == value_str_len) { + Py_INCREF(value); + value_unescape = value; + } + else { + value_unescape = PyUnicode_FromStringAndSize(value_unescape_str, value_unescape_str_len); + } + + PyMem_FREE(value_unescape_str); + + return value_unescape; +} + static PyMethodDef meth_bpy_script_paths = { "script_paths", (PyCFunction)bpy_script_paths, @@ -328,6 +360,12 @@ static PyMethodDef meth_bpy_escape_identifier = { METH_O, bpy_escape_identifier_doc, }; +static PyMethodDef meth_bpy_unescape_identifier = { + "unescape_identifier", + (PyCFunction)bpy_unescape_identifier, + METH_O, + bpy_unescape_identifier_doc, +}; static PyObject *bpy_import_test(const char *modname) { @@ -429,6 +467,9 @@ void BPy_init_modules(struct bContext *C) PyModule_AddObject(mod, meth_bpy_escape_identifier.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_escape_identifier, NULL)); + PyModule_AddObject(mod, + meth_bpy_unescape_identifier.ml_name, + (PyObject *)PyCFunction_New(&meth_bpy_unescape_identifier, NULL)); /* register funcs (bpy_rna.c) */ PyModule_AddObject(mod, diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c index bc3d8b2c360..c6f0fbd3a2b 100644 --- a/source/blender/python/intern/bpy_library_load.c +++ b/source/blender/python/intern/bpy_library_load.c @@ -44,6 +44,8 @@ #include "BLO_readfile.h" +#include "MEM_guardedalloc.h" + #include "bpy_capi_utils.h" #include "bpy_library.h" @@ -225,7 +227,7 @@ static PyObject *_bpy_names(BPy_Library *self, int blocktype) PyList_SET_ITEM(list, counter, PyUnicode_FromString((char *)l->link)); counter++; } - BLI_linklist_free(names, free); /* free linklist *and* each node's data */ + BLI_linklist_freeN(names); /* free linklist *and* each node's data */ } return list; diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c index d45c8e8b131..354086ef4c3 100644 --- a/source/blender/python/intern/bpy_props.c +++ b/source/blender/python/intern/bpy_props.c @@ -43,6 +43,8 @@ #include "MEM_guardedalloc.h" +#include "DNA_ID.h" /* MAX_IDPROP_NAME */ + #include "../generic/py_capi_utils.h" /* initial definition of callback slots we'll probably have more than 1 */ @@ -3494,7 +3496,6 @@ PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw) if (!RNA_struct_is_a(ptype, &RNA_PropertyGroup)) { PyErr_Format(PyExc_TypeError, "CollectionProperty(...) expected an RNA type derived from %.200s", - RNA_struct_ui_name(&RNA_ID), RNA_struct_ui_name(&RNA_PropertyGroup)); return NULL; } diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt index d1f69ddfc02..0046474d064 100644 --- a/source/blender/render/CMakeLists.txt +++ b/source/blender/render/CMakeLists.txt @@ -60,9 +60,9 @@ set(SRC RE_texture.h intern/initrender.h + intern/pipeline.h intern/render_result.h intern/render_types.h - intern/pipeline.h intern/texture_common.h intern/zbuf.h ) diff --git a/source/blender/render/RE_pipeline.h b/source/blender/render/RE_pipeline.h index 4dd2b300700..3e73ac77fc6 100644 --- a/source/blender/render/RE_pipeline.h +++ b/source/blender/render/RE_pipeline.h @@ -114,7 +114,7 @@ typedef struct RenderResult { /* target image size */ int rectx, recty; - short crop, sample_nr; + short sample_nr; /* The following rect32, rectf and rectz buffers are for temporary storage only, * for RenderResult structs created in #RE_AcquireResultImage - which do not have RenderView */ diff --git a/source/blender/render/intern/engine.c b/source/blender/render/intern/engine.c index 769077c0e8c..5685911c42e 100644 --- a/source/blender/render/intern/engine.c +++ b/source/blender/render/intern/engine.c @@ -288,7 +288,7 @@ RenderResult *RE_engine_begin_result( disprect.ymin = y; disprect.ymax = y + h; - result = render_result_new(re, &disprect, 0, RR_USE_MEM, layername, viewname); + result = render_result_new(re, &disprect, RR_USE_MEM, layername, viewname); /* todo: make this thread safe */ @@ -846,7 +846,7 @@ int RE_engine_render(Render *re, int do_all) if ((type->flag & RE_USE_SAVE_BUFFERS) && (re->r.scemode & R_EXR_TILE_FILE)) { savebuffers = RR_USE_EXR; } - re->result = render_result_new(re, &re->disprect, 0, savebuffers, RR_ALL_LAYERS, RR_ALL_VIEWS); + re->result = render_result_new(re, &re->disprect, savebuffers, RR_ALL_LAYERS, RR_ALL_VIEWS); } BLI_rw_mutex_unlock(&re->resultmutex); diff --git a/source/blender/render/intern/pipeline.c b/source/blender/render/intern/pipeline.c index 3d19e5e6c15..f484977d2b4 100644 --- a/source/blender/render/intern/pipeline.c +++ b/source/blender/render/intern/pipeline.c @@ -88,7 +88,8 @@ #include "RE_pipeline.h" #include "RE_texture.h" -#include "SEQ_sequencer.h" +#include "SEQ_relations.h" +#include "SEQ_render.h" #include "../../windowmanager/WM_api.h" /* XXX */ #include "../../windowmanager/wm_window.h" /* XXX */ @@ -905,7 +906,7 @@ static void render_result_rescale(Render *re) if (src_rectf != NULL) { float *dst_rectf = NULL; - re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, ""); + re->result = render_result_new(re, &re->disprect, RR_USE_MEM, RR_ALL_LAYERS, ""); if (re->result != NULL) { dst_rectf = RE_RenderViewGetById(re->result, 0)->rectf; @@ -1162,7 +1163,7 @@ static void render_result_uncrop(Render *re) /* weak is: it chances disprect from border */ render_result_disprect_to_full_resolution(re); - rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); + rres = render_result_new(re, &re->disprect, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); rres->stamp_data = BKE_stamp_data_copy(re->result->stamp_data); render_result_clone_passes(re, rres, NULL); @@ -1358,7 +1359,7 @@ static void do_render_composite(Render *re) if ((re->r.mode & R_CROP) == 0) { render_result_disprect_to_full_resolution(re); } - re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); + re->result = render_result_new(re, &re->disprect, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); BLI_rw_mutex_unlock(&re->resultmutex); @@ -1548,7 +1549,7 @@ static void do_render_seq(Render *re) if (recurs_depth == 0) { /* With nested scenes, only free on top-level. */ Editing *ed = re->pipeline_scene_eval->ed; if (ed) { - BKE_sequencer_free_imbuf(re->pipeline_scene_eval, &ed->seqbase, true); + SEQ_relations_free_imbuf(re->pipeline_scene_eval, &ed->seqbase, true); } } IMB_freeImBuf(ibuf_arr[view_id]); @@ -1596,7 +1597,7 @@ static void do_render_all_options(Render *re) /* ensure no images are in memory from previous animated sequences */ BKE_image_all_free_anim_ibufs(re->main, re->r.cfra); - BKE_sequencer_all_free_anim_ibufs(re->scene, re->r.cfra); + SEQ_relations_free_all_anim_ibufs(re->scene, re->r.cfra); if (RE_engine_render(re, 1)) { /* in this case external render overrides all */ diff --git a/source/blender/render/intern/render_result.c b/source/blender/render/intern/render_result.c index dfce51ec3ab..1ed894751ce 100644 --- a/source/blender/render/intern/render_result.c +++ b/source/blender/render/intern/render_result.c @@ -285,12 +285,8 @@ RenderPass *render_layer_add_pass(RenderResult *rr, /* will read info from Render *re to define layers */ /* called in threads */ /* re->winx,winy is coordinate space of entire image, partrct the part within */ -RenderResult *render_result_new(Render *re, - rcti *partrct, - int crop, - int savebuffers, - const char *layername, - const char *viewname) +RenderResult *render_result_new( + Render *re, rcti *partrct, int savebuffers, const char *layername, const char *viewname) { RenderResult *rr; RenderLayer *rl; @@ -308,9 +304,7 @@ RenderResult *render_result_new(Render *re, rr->rectx = rectx; rr->recty = recty; rr->renrect.xmin = 0; - rr->renrect.xmax = rectx - 2 * crop; - /* crop is one or two extra pixels rendered for filtering, is used for merging and display too */ - rr->crop = crop; + rr->renrect.xmax = rectx; /* tilerect is relative coordinates within render disprect. do not subtract crop yet */ rr->tilerect.xmin = partrct->xmin - re->disprect.xmin; @@ -827,20 +821,8 @@ static void do_merge_tile( copylen = tilex = rrpart->rectx; tiley = rrpart->recty; - if (rrpart->crop) { /* filters add pixel extra */ - tile += pixsize * (rrpart->crop + ((size_t)rrpart->crop) * tilex); - - copylen = tilex - 2 * rrpart->crop; - tiley -= 2 * rrpart->crop; - - ofs = (((size_t)rrpart->tilerect.ymin) + rrpart->crop) * rr->rectx + - (rrpart->tilerect.xmin + rrpart->crop); - target += pixsize * ofs; - } - else { - ofs = (((size_t)rrpart->tilerect.ymin) * rr->rectx + rrpart->tilerect.xmin); - target += pixsize * ofs; - } + ofs = (((size_t)rrpart->tilerect.ymin) * rr->rectx + rrpart->tilerect.xmin); + target += pixsize * ofs; copylen *= sizeof(float) * pixsize; tilex *= pixsize; @@ -1107,7 +1089,7 @@ static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart, cons { RenderLayer *rlp, *rl; RenderPass *rpassp; - int offs, partx, party; + int partx, party; BLI_thread_lock(LOCK_IMAGE); @@ -1120,13 +1102,6 @@ static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart, cons continue; } - if (rrpart->crop) { /* filters add pixel extra */ - offs = (rrpart->crop + rrpart->crop * rrpart->rectx); - } - else { - offs = 0; - } - /* passes are allocated in sync */ for (rpassp = rlp->passes.first; rpassp; rpassp = rpassp->next) { const int xstride = rpassp->channels; @@ -1141,13 +1116,13 @@ static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart, cons fullname, xstride, xstride * rrpart->rectx, - rpassp->rect + a + xstride * offs); + rpassp->rect + a); } } } - party = rrpart->tilerect.ymin + rrpart->crop; - partx = rrpart->tilerect.xmin + rrpart->crop; + party = rrpart->tilerect.ymin; + partx = rrpart->tilerect.xmin; for (rlp = rrpart->layers.first; rlp; rlp = rlp->next) { rl = RE_GetRenderLayer(rr, rlp->name); @@ -1267,7 +1242,7 @@ void render_result_exr_file_end(Render *re, RenderEngine *engine) /* Create new render result in memory instead of on disk. */ BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); render_result_free_list(&re->fullresult, re->result); - re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); + re->result = render_result_new(re, &re->disprect, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); BLI_rw_mutex_unlock(&re->resultmutex); LISTBASE_FOREACH (RenderLayer *, rl, &re->result->layers) { @@ -1429,7 +1404,7 @@ bool render_result_exr_file_cache_read(Render *re) char *root = U.render_cachedir; RE_FreeRenderResult(re->result); - re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); + re->result = render_result_new(re, &re->disprect, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); /* First try cache. */ render_result_exr_file_cache_path(re->scene, root, str); diff --git a/source/blender/render/intern/render_result.h b/source/blender/render/intern/render_result.h index 5c487223e94..67edd075e24 100644 --- a/source/blender/render/intern/render_result.h +++ b/source/blender/render/intern/render_result.h @@ -51,7 +51,6 @@ extern "C" { struct RenderResult *render_result_new(struct Render *re, struct rcti *partrct, - int crop, int savebuffers, const char *layername, const char *viewname); diff --git a/source/blender/render/intern/texture_pointdensity.c b/source/blender/render/intern/texture_pointdensity.c index e2568e0a013..4254f6b0aa6 100644 --- a/source/blender/render/intern/texture_pointdensity.c +++ b/source/blender/render/intern/texture_pointdensity.c @@ -44,6 +44,7 @@ #include "BKE_colorband.h" #include "BKE_colortools.h" +#include "BKE_customdata.h" #include "BKE_deform.h" #include "BKE_lattice.h" #include "BKE_object.h" diff --git a/source/blender/sequencer/CMakeLists.txt b/source/blender/sequencer/CMakeLists.txt index 18755e7e6bc..82e303806b3 100644 --- a/source/blender/sequencer/CMakeLists.txt +++ b/source/blender/sequencer/CMakeLists.txt @@ -21,6 +21,7 @@ set(INC . intern + ../blenfont ../blenkernel ../blenlib ../blenloader @@ -30,7 +31,6 @@ set(INC ../makesdna ../makesrna ../render - ../blenfont ../windowmanager ../../../intern/atomic ../../../intern/guardedalloc @@ -44,7 +44,22 @@ set(INC_SYS ) set(SRC + SEQ_add.h + SEQ_clipboard.h + SEQ_edit.h + SEQ_effects.h + SEQ_iterator.h + SEQ_modifier.h + SEQ_prefetch.h + SEQ_proxy.h + SEQ_relations.h + SEQ_render.h + SEQ_select.h SEQ_sequencer.h + SEQ_sound.h + SEQ_time.h + SEQ_transform.h + SEQ_utils.h intern/clipboard.c intern/effects.c diff --git a/source/blender/sequencer/SEQ_add.h b/source/blender/sequencer/SEQ_add.h new file mode 100644 index 00000000000..9ed617e6963 --- /dev/null +++ b/source/blender/sequencer/SEQ_add.h @@ -0,0 +1,89 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2004 Blender Foundation. + * All rights reserved. + */ + +#pragma once + +/** \file + * \ingroup sequencer + */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct Scene; +struct Sequence; +struct ListBase; +struct bContext; + +/* api for adding new sequence strips */ +typedef struct SeqLoadInfo { + int start_frame; + int end_frame; + int channel; + int flag; /* use sound, replace sel */ + int type; + int len; /* only for image strips */ + char path[1024]; /* 1024 = FILE_MAX */ + eSeqImageFitMethod fit_method; + + /* multiview */ + char views_format; + struct Stereo3dFormat *stereo3d_format; + + /* return values */ + char name[64]; + struct Sequence *seq_sound; /* for movie's */ + int tot_success; + int tot_error; +} SeqLoadInfo; + +/* SeqLoadInfo.flag */ +#define SEQ_LOAD_REPLACE_SEL (1 << 0) +#define SEQ_LOAD_FRAME_ADVANCE (1 << 1) +#define SEQ_LOAD_MOVIE_SOUND (1 << 2) +#define SEQ_LOAD_SOUND_CACHE (1 << 3) +#define SEQ_LOAD_SYNC_FPS (1 << 4) +#define SEQ_LOAD_SOUND_MONO (1 << 5) + +/* use as an api function */ +typedef struct Sequence *(*SeqLoadFn)(struct bContext *, ListBase *, struct SeqLoadInfo *); + +struct Sequence *SEQ_add_image_strip(struct bContext *C, + ListBase *seqbasep, + struct SeqLoadInfo *seq_load); +struct Sequence *SEQ_add_sound_strip(struct bContext *C, + ListBase *seqbasep, + struct SeqLoadInfo *seq_load); +struct Sequence *SEQ_add_movie_strip(struct bContext *C, + ListBase *seqbasep, + struct SeqLoadInfo *seq_load); +void SEQ_add_reload_new_file(struct Main *bmain, + struct Scene *scene, + struct Sequence *seq, + const bool lock_range); +void SEQ_add_movie_reload_if_needed(struct Main *bmain, + struct Scene *scene, + struct Sequence *seq, + bool *r_was_reloaded, + bool *r_can_produce_frames); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/sequencer/SEQ_clipboard.h b/source/blender/sequencer/SEQ_clipboard.h new file mode 100644 index 00000000000..4b2bf69a8ac --- /dev/null +++ b/source/blender/sequencer/SEQ_clipboard.h @@ -0,0 +1,41 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2004 Blender Foundation. + * All rights reserved. + */ + +#pragma once + +/** \file + * \ingroup sequencer + */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct ListBase; +struct Main; + +extern struct ListBase seqbase_clipboard; +extern int seqbase_clipboard_frame; +void SEQ_clipboard_pointers_store(struct Main *bmain, struct ListBase *seqbase); +void SEQ_clipboard_pointers_restore(struct ListBase *seqbase, struct Main *bmain); +void SEQ_clipboard_free(void); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/sequencer/SEQ_edit.h b/source/blender/sequencer/SEQ_edit.h new file mode 100644 index 00000000000..b0c5d46d713 --- /dev/null +++ b/source/blender/sequencer/SEQ_edit.h @@ -0,0 +1,59 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2004 Blender Foundation. + * All rights reserved. + */ + +#pragma once + +/** \file + * \ingroup sequencer + */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct Scene; +struct Sequence; +struct Main; +struct ListBase; + +int SEQ_edit_sequence_swap(struct Sequence *seq_a, struct Sequence *seq_b, const char **error_str); +void SEQ_edit_flag_for_removal(struct Scene *scene, + struct ListBase *seqbase, + struct Sequence *seq); +void SEQ_edit_remove_flagged_sequences(struct Scene *scene, struct ListBase *seqbase); +void SEQ_edit_update_muting(struct Editing *ed); + +typedef enum eSeqSplitMethod { + SEQ_SPLIT_SOFT, + SEQ_SPLIT_HARD, +} eSeqSplitMethod; + +struct Sequence *SEQ_edit_strip_split(struct Main *bmain, + struct Scene *scene, + struct ListBase *seqbase, + struct Sequence *seq, + const int timeline_frame, + const eSeqSplitMethod method); +bool SEQ_edit_remove_gaps(struct Scene *scene, + struct ListBase *seqbase, + const int initial_frame, + const bool remove_all_gaps); +#ifdef __cplusplus +} +#endif diff --git a/source/blender/sequencer/SEQ_effects.h b/source/blender/sequencer/SEQ_effects.h new file mode 100644 index 00000000000..1258efd2694 --- /dev/null +++ b/source/blender/sequencer/SEQ_effects.h @@ -0,0 +1,118 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2004 Blender Foundation. + * All rights reserved. + */ + +#pragma once + +/** \file + * \ingroup sequencer + */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct Sequence; +struct ImBuf; +struct SeqRenderData; +struct TextVars; + +/* Wipe effect */ +enum { + DO_SINGLE_WIPE, + DO_DOUBLE_WIPE, + /* DO_BOX_WIPE, */ /* UNUSED */ + /* DO_CROSS_WIPE, */ /* UNUSED */ + DO_IRIS_WIPE, + DO_CLOCK_WIPE, +}; + +struct SeqEffectHandle { + bool multithreaded; + bool supports_mask; + + /* constructors & destructor */ + /* init is _only_ called on first creation */ + void (*init)(struct Sequence *seq); + + /* number of input strips needed + * (called directly after construction) */ + int (*num_inputs)(void); + + /* load is called first time after readblenfile in + * get_sequence_effect automatically */ + void (*load)(struct Sequence *seqconst); + + /* duplicate */ + void (*copy)(struct Sequence *dst, struct Sequence *src, const int flag); + + /* destruct */ + void (*free)(struct Sequence *seq, const bool do_id_user); + + /* returns: -1: no input needed, + * 0: no early out, + * 1: out = ibuf1, + * 2: out = ibuf2 */ + int (*early_out)(struct Sequence *seq, float facf0, float facf1); + + /* stores the y-range of the effect IPO */ + void (*store_icu_yrange)(struct Sequence *seq, short adrcode, float *ymin, float *ymax); + + /* stores the default facf0 and facf1 if no IPO is present */ + void (*get_default_fac)(struct Sequence *seq, float timeline_frame, float *facf0, float *facf1); + + /* execute the effect + * sequence effects are only required to either support + * float-rects or byte-rects + * (mixed cases are handled one layer up...) */ + + struct ImBuf *(*execute)(const struct SeqRenderData *context, + struct Sequence *seq, + float timeline_frame, + float facf0, + float facf1, + struct ImBuf *ibuf1, + struct ImBuf *ibuf2, + struct ImBuf *ibuf3); + + struct ImBuf *(*init_execution)(const struct SeqRenderData *context, + struct ImBuf *ibuf1, + struct ImBuf *ibuf2, + struct ImBuf *ibuf3); + + void (*execute_slice)(const struct SeqRenderData *context, + struct Sequence *seq, + float timeline_frame, + float facf0, + float facf1, + struct ImBuf *ibuf1, + struct ImBuf *ibuf2, + struct ImBuf *ibuf3, + int start_line, + int total_lines, + struct ImBuf *out); +}; + +struct SeqEffectHandle SEQ_effect_handle_get(struct Sequence *seq); +int SEQ_effect_get_num_inputs(int seq_type); +void SEQ_effect_text_font_unload(struct TextVars *data, const bool do_id_user); +void SEQ_effect_text_font_load(struct TextVars *data, const bool do_id_user); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/sequencer/SEQ_iterator.h b/source/blender/sequencer/SEQ_iterator.h new file mode 100644 index 00000000000..05fd706a8de --- /dev/null +++ b/source/blender/sequencer/SEQ_iterator.h @@ -0,0 +1,75 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2004 Blender Foundation. + * All rights reserved. + */ + +#pragma once + +/** \file + * \ingroup sequencer + */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct Sequence; +struct Editing; + +typedef struct SeqIterator { + struct Sequence **array; + int tot, cur; + + struct Sequence *seq; + int valid; +} SeqIterator; + +#define SEQ_ALL_BEGIN(ed, _seq) \ + { \ + SeqIterator iter_macro; \ + for (SEQ_iterator_begin(ed, &iter_macro, false); iter_macro.valid; \ + SEQ_iterator_next(&iter_macro)) { \ + _seq = iter_macro.seq; + +#define SEQ_ALL_END \ + } \ + SEQ_iterator_end(&iter_macro); \ + } \ + ((void)0) + +#define SEQ_CURRENT_BEGIN(_ed, _seq) \ + { \ + SeqIterator iter_macro; \ + for (SEQ_iterator_begin(_ed, &iter_macro, true); iter_macro.valid; \ + SEQ_iterator_next(&iter_macro)) { \ + _seq = iter_macro.seq; + +#define SEQ_CURRENT_END SEQ_ALL_END + +void SEQ_iterator_begin(struct Editing *ed, SeqIterator *iter, const bool use_current_sequences); +void SEQ_iterator_next(SeqIterator *iter); +void SEQ_iterator_end(SeqIterator *iter); +int SEQ_iterator_seqbase_recursive_apply(struct ListBase *seqbase, + int (*apply_fn)(struct Sequence *seq, void *), + void *arg); +int SEQ_iterator_recursive_apply(struct Sequence *seq, + int (*apply_fn)(struct Sequence *, void *), + void *arg); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/sequencer/SEQ_modifier.h b/source/blender/sequencer/SEQ_modifier.h new file mode 100644 index 00000000000..74948db24d4 --- /dev/null +++ b/source/blender/sequencer/SEQ_modifier.h @@ -0,0 +1,88 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2004 Blender Foundation. + * All rights reserved. + */ + +#pragma once + +/** \file + * \ingroup sequencer + */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct Scene; +struct Sequence; +struct ListBase; +struct SequenceModifierData; +struct SeqRenderData; +struct ImBuf; +struct BlendDataReader; +struct BlendLibReader; +struct BlendWriter; + +typedef struct SequenceModifierTypeInfo { + /* default name for the modifier */ + char name[64]; /* MAX_NAME */ + + /* DNA structure name used on load/save filed */ + char struct_name[64]; /* MAX_NAME */ + + /* size of modifier data structure, used by allocation */ + int struct_size; + + /* data initialization */ + void (*init_data)(struct SequenceModifierData *smd); + + /* free data used by modifier, + * only modifier-specific data should be freed, modifier descriptor would + * be freed outside of this callback + */ + void (*free_data)(struct SequenceModifierData *smd); + + /* copy data from one modifier to another */ + void (*copy_data)(struct SequenceModifierData *smd, struct SequenceModifierData *target); + + /* apply modifier on a given image buffer */ + void (*apply)(struct SequenceModifierData *smd, struct ImBuf *ibuf, struct ImBuf *mask); +} SequenceModifierTypeInfo; + +const struct SequenceModifierTypeInfo *SEQ_modifier_type_info_get(int type); +struct SequenceModifierData *SEQ_modifier_new(struct Sequence *seq, const char *name, int type); +bool SEQ_modifier_remove(struct Sequence *seq, struct SequenceModifierData *smd); +void SEQ_modifier_clear(struct Sequence *seq); +void SEQ_modifier_free(struct SequenceModifierData *smd); +void SEQ_modifier_unique_name(struct Sequence *seq, struct SequenceModifierData *smd); +struct SequenceModifierData *SEQ_modifier_find_by_name(struct Sequence *seq, const char *name); +struct ImBuf *SEQ_modifier_apply_stack(const struct SeqRenderData *context, + struct Sequence *seq, + struct ImBuf *ibuf, + int timeline_frame); +void SEQ_modifier_list_copy(struct Sequence *seqn, struct Sequence *seq); +int SEQ_sequence_supports_modifiers(struct Sequence *seq); + +void SEQ_modifier_blend_write(struct BlendWriter *writer, struct ListBase *modbase); +void SEQ_modifier_blend_read_data(struct BlendDataReader *reader, struct ListBase *lb); +void SEQ_modifier_blend_read_lib(struct BlendLibReader *reader, + struct Scene *scene, + struct ListBase *lb); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/sequencer/SEQ_prefetch.h b/source/blender/sequencer/SEQ_prefetch.h new file mode 100644 index 00000000000..2ec8d509a91 --- /dev/null +++ b/source/blender/sequencer/SEQ_prefetch.h @@ -0,0 +1,39 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2004 Blender Foundation. + * All rights reserved. + */ + +#pragma once + +/** \file + * \ingroup sequencer + */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct Scene; +struct Main; + +void SEQ_prefetch_stop_all(void); +void SEQ_prefetch_stop(struct Scene *scene); +bool SEQ_prefetch_need_redraw(struct Main *bmain, struct Scene *scene); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/sequencer/SEQ_proxy.h b/source/blender/sequencer/SEQ_proxy.h new file mode 100644 index 00000000000..b909ac7b02d --- /dev/null +++ b/source/blender/sequencer/SEQ_proxy.h @@ -0,0 +1,57 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2004 Blender Foundation. + * All rights reserved. + */ + +#pragma once + +/** \file + * \ingroup sequencer + */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct Scene; +struct Main; +struct GSet; +struct Sequence; +struct ListBase; +struct Depsgraph; +struct SeqIndexBuildContext; +struct ListBase; + +bool SEQ_proxy_rebuild_context(struct Main *bmain, + struct Depsgraph *depsgraph, + struct Scene *scene, + struct Sequence *seq, + struct GSet *file_list, + struct ListBase *queue); +void SEQ_proxy_rebuild(struct SeqIndexBuildContext *context, + short *stop, + short *do_update, + float *progress); +void SEQ_proxy_rebuild_finish(struct SeqIndexBuildContext *context, bool stop); +void SEQ_proxy_set(struct Sequence *seq, bool value); +bool SEQ_can_use_proxy(struct Sequence *seq, int psize); +int SEQ_rendersize_to_proxysize(int render_size); +double SEQ_rendersize_to_scale_factor(int size); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/sequencer/SEQ_relations.h b/source/blender/sequencer/SEQ_relations.h new file mode 100644 index 00000000000..b2e7ac9f007 --- /dev/null +++ b/source/blender/sequencer/SEQ_relations.h @@ -0,0 +1,70 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2004 Blender Foundation. + * All rights reserved. + */ + +#pragma once + +/** \file + * \ingroup sequencer + */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct Scene; +struct Sequence; +struct Main; +struct ListBase; +struct ReportList; +struct MovieClip; + +void SEQ_relations_sequence_free_anim(struct Sequence *seq); +void SEQ_relations_update_changed_seq_and_deps(struct Scene *scene, + struct Sequence *changed_seq, + int len_change, + int ibuf_change); +bool SEQ_relations_check_scene_recursion(struct Scene *scene, struct ReportList *reports); +bool SEQ_relations_render_loop_check(struct Sequence *seq_main, struct Sequence *seq); +void SEQ_relations_free_imbuf(struct Scene *scene, struct ListBase *seqbasep, bool for_render); +void SEQ_relations_invalidate_cache_raw(struct Scene *scene, struct Sequence *seq); +void SEQ_relations_invalidate_cache_preprocessed(struct Scene *scene, struct Sequence *seq); +void SEQ_relations_invalidate_cache_composite(struct Scene *scene, struct Sequence *seq); +void SEQ_relations_invalidate_dependent(struct Scene *scene, struct Sequence *seq); +void SEQ_relations_invalidate_scene_strips(struct Main *bmain, struct Scene *scene_target); +void SEQ_relations_invalidate_movieclip_strips(struct Main *bmain, struct MovieClip *clip_target); +void SEQ_relations_invalidate_cache_in_range(struct Scene *scene, + struct Sequence *seq, + struct Sequence *range_mask, + int invalidate_types); +void SEQ_relations_free_all_anim_ibufs(struct Scene *scene, int timeline_frame); +/* A debug and development function which checks whether sequences have unique UUIDs. + * Errors will be reported to the console. */ +void SEQ_relations_check_uuids_unique_and_report(const struct Scene *scene); +/* Generate new UUID for the given sequence. */ +void SEQ_relations_session_uuid_generate(struct Sequence *sequence); + +void SEQ_cache_cleanup(struct Scene *scene); +void SEQ_cache_iterate( + struct Scene *scene, + void *userdata, + bool callback_init(void *userdata, size_t item_count), + bool callback_iter(void *userdata, struct Sequence *seq, int timeline_frame, int cache_type)); +#ifdef __cplusplus +} +#endif diff --git a/source/blender/sequencer/SEQ_render.h b/source/blender/sequencer/SEQ_render.h new file mode 100644 index 00000000000..fea68c14c7b --- /dev/null +++ b/source/blender/sequencer/SEQ_render.h @@ -0,0 +1,88 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2004 Blender Foundation. + * All rights reserved. + */ + +#pragma once + +/** \file + * \ingroup sequencer + */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct Scene; +struct Editing; +struct Sequence; +struct bSound; +struct Main; +struct ListBase; + +typedef enum eSeqTaskId { + SEQ_TASK_MAIN_RENDER, + SEQ_TASK_PREFETCH_RENDER, +} eSeqTaskId; + +typedef struct SeqRenderData { + struct Main *bmain; + struct Depsgraph *depsgraph; + struct Scene *scene; + int rectx; + int recty; + int preview_render_size; + int for_render; + int motion_blur_samples; + float motion_blur_shutter; + bool skip_cache; + bool is_proxy_render; + bool is_prefetch_render; + int view_id; + /* ID of task for asigning temp cache entries to particular task(thread, etc.) */ + eSeqTaskId task_id; + + /* special case for OpenGL render */ + struct GPUOffScreen *gpu_offscreen; + // int gpu_samples; + // bool gpu_full_samples; +} SeqRenderData; + +struct ImBuf *SEQ_render_give_ibuf(const SeqRenderData *context, + float timeline_frame, + int chanshown); +struct ImBuf *SEQ_render_give_ibuf_direct(const SeqRenderData *context, + float timeline_frame, + struct Sequence *seq); +void SEQ_render_init_colorspace(struct Sequence *seq); +void SEQ_render_new_render_data(struct Main *bmain, + struct Depsgraph *depsgraph, + struct Scene *scene, + int rectx, + int recty, + int preview_render_size, + int for_render, + SeqRenderData *r_context); +int SEQ_render_evaluate_frame(struct ListBase *seqbase, int timeline_frame); +struct StripElem *SEQ_render_give_stripelem(struct Sequence *seq, int timeline_frame); + +void SEQ_render_imbuf_from_sequencer_space(struct Scene *scene, struct ImBuf *ibuf); +void SEQ_render_pixel_from_sequencer_space_v4(struct Scene *scene, float pixel[4]); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/sequencer/SEQ_select.h b/source/blender/sequencer/SEQ_select.h new file mode 100644 index 00000000000..5a65f9c0d8c --- /dev/null +++ b/source/blender/sequencer/SEQ_select.h @@ -0,0 +1,41 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2004 Blender Foundation. + * All rights reserved. + */ + +#pragma once + +/** \file + * \ingroup sequencer + */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct Scene; +struct Sequence; + +struct Sequence *SEQ_select_active_get(struct Scene *scene); +int SEQ_select_active_get_pair(struct Scene *scene, + struct Sequence **seq_act, + struct Sequence **seq_other); +void SEQ_select_active_set(struct Scene *scene, struct Sequence *seq); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/sequencer/SEQ_sequencer.h b/source/blender/sequencer/SEQ_sequencer.h index 11e213d842d..37ad71b64bd 100644 --- a/source/blender/sequencer/SEQ_sequencer.h +++ b/source/blender/sequencer/SEQ_sequencer.h @@ -27,6 +27,8 @@ extern "C" { #endif +#include "DNA_scene_types.h" + struct Depsgraph; struct Editing; struct GPUOffScreen; @@ -47,16 +49,7 @@ struct bSound; struct BlendWriter; struct BlendDataReader; struct BlendLibReader; - -/* Wipe effect */ -enum { - DO_SINGLE_WIPE, - DO_DOUBLE_WIPE, - /* DO_BOX_WIPE, */ /* UNUSED */ - /* DO_CROSS_WIPE, */ /* UNUSED */ - DO_IRIS_WIPE, - DO_CLOCK_WIPE, -}; +struct SequencerToolSettings; /* RNA enums, just to be more readable */ enum { @@ -68,533 +61,39 @@ enum { SEQ_SIDE_NO_CHANGE, }; -/* ********************************************************************** - * sequencer.c - * - * Sequencer iterators - * ********************************************************************** - */ - -typedef struct SeqIterator { - struct Sequence **array; - int tot, cur; - - struct Sequence *seq; - int valid; -} SeqIterator; - -#define SEQ_ALL_BEGIN(ed, _seq) \ - { \ - SeqIterator iter_macro; \ - for (BKE_sequence_iterator_begin(ed, &iter_macro, false); iter_macro.valid; \ - BKE_sequence_iterator_next(&iter_macro)) { \ - _seq = iter_macro.seq; - -#define SEQ_ALL_END \ - } \ - BKE_sequence_iterator_end(&iter_macro); \ - } \ - ((void)0) - -#define SEQ_CURRENT_BEGIN(_ed, _seq) \ - { \ - SeqIterator iter_macro; \ - for (BKE_sequence_iterator_begin(_ed, &iter_macro, true); iter_macro.valid; \ - BKE_sequence_iterator_next(&iter_macro)) { \ - _seq = iter_macro.seq; - -#define SEQ_CURRENT_END SEQ_ALL_END - -void BKE_sequence_iterator_begin(struct Editing *ed, - SeqIterator *iter, - const bool use_current_sequences); -void BKE_sequence_iterator_next(SeqIterator *iter); -void BKE_sequence_iterator_end(SeqIterator *iter); - -/* ********************************************************************** - * render.c - * - * Sequencer render functions - * ********************************************************************** - */ - -typedef enum eSeqTaskId { - SEQ_TASK_MAIN_RENDER, - SEQ_TASK_PREFETCH_RENDER, -} eSeqTaskId; - -typedef struct SeqRenderData { - struct Main *bmain; - struct Depsgraph *depsgraph; - struct Scene *scene; - int rectx; - int recty; - int preview_render_size; - int for_render; - int motion_blur_samples; - float motion_blur_shutter; - bool skip_cache; - bool is_proxy_render; - bool is_prefetch_render; - int view_id; - /* ID of task for asigning temp cache entries to particular task(thread, etc.) */ - eSeqTaskId task_id; - - /* special case for OpenGL render */ - struct GPUOffScreen *gpu_offscreen; - // int gpu_samples; - // bool gpu_full_samples; -} SeqRenderData; - -struct ImBuf *SEQ_render_give_ibuf(const SeqRenderData *context, - float timeline_frame, - int chanshown); -struct ImBuf *SEQ_render_give_ibuf_direct(const SeqRenderData *context, - float timeline_frame, - struct Sequence *seq); -void SEQ_render_init_colorspace(struct Sequence *seq); -void SEQ_render_new_render_data(struct Main *bmain, - struct Depsgraph *depsgraph, - struct Scene *scene, - int rectx, - int recty, - int preview_render_size, - int for_render, - SeqRenderData *r_context); -int SEQ_render_evaluate_frame(struct Scene *scene, int timeline_frame); -struct StripElem *SEQ_render_give_stripelem(struct Sequence *seq, int timeline_frame); - -/* ********************************************************************** - * render.c - * - * Sequencer color space functions - * ********************************************************************** */ - -void SEQ_render_imbuf_from_sequencer_space(struct Scene *scene, struct ImBuf *ibuf); -void SEQ_render_pixel_from_sequencer_space_v4(struct Scene *scene, float pixel[4]); - -/* ********************************************************************** - * sequencer.c - * - * Sequencer scene functions - * ********************************************************************** */ - -struct Editing *BKE_sequencer_editing_get(struct Scene *scene, bool alloc); -struct Editing *BKE_sequencer_editing_ensure(struct Scene *scene); -void BKE_sequencer_editing_free(struct Scene *scene, const bool do_id_user); -void BKE_sequencer_sort(struct Scene *scene); -struct Sequence *BKE_sequencer_from_elem(ListBase *seqbase, struct StripElem *se); -struct Sequence *BKE_sequencer_active_get(struct Scene *scene); -int BKE_sequencer_active_get_pair(struct Scene *scene, - struct Sequence **seq_act, - struct Sequence **seq_other); -void BKE_sequencer_active_set(struct Scene *scene, struct Sequence *seq); -struct Mask *BKE_sequencer_mask_get(struct Scene *scene); -/* apply functions recursively */ -int BKE_sequencer_base_recursive_apply(struct ListBase *seqbase, - int (*apply_fn)(struct Sequence *seq, void *), - void *arg); -int BKE_sequencer_recursive_apply(struct Sequence *seq, - int (*apply_fn)(struct Sequence *, void *), - void *arg); -float BKE_sequence_get_fps(struct Scene *scene, struct Sequence *seq); -int BKE_sequencer_find_next_prev_edit(struct Scene *scene, - int timeline_frame, - const short side, - const bool do_skip_mute, - const bool do_center, - const bool do_unselected); -/* maintenance functions, mostly for RNA */ -void BKE_sequence_free(struct Scene *scene, struct Sequence *seq, const bool do_clean_animdata); -void BKE_sequence_free_anim(struct Sequence *seq); -const char *BKE_sequence_give_name(struct Sequence *seq); -ListBase *BKE_sequence_seqbase_get(struct Sequence *seq, int *r_offset); -void BKE_sequence_calc(struct Scene *scene, struct Sequence *seq); -void BKE_sequence_calc_disp(struct Scene *scene, struct Sequence *seq); -void BKE_sequence_reload_new_file(struct Main *bmain, - struct Scene *scene, - struct Sequence *seq, - const bool lock_range); -void BKE_sequence_movie_reload_if_needed(struct Main *bmain, - struct Scene *scene, - struct Sequence *seq, - bool *r_was_reloaded, - bool *r_can_produce_frames); -void BKE_sequence_alpha_mode_from_extension(struct Sequence *seq); -void BKE_sequencer_update_changed_seq_and_deps(struct Scene *scene, - struct Sequence *changed_seq, - int len_change, - int ibuf_change); -bool BKE_sequencer_check_scene_recursion(struct Scene *scene, struct ReportList *reports); -bool BKE_sequencer_render_loop_check(struct Sequence *seq_main, struct Sequence *seq); -int BKE_sequencer_cmp_time_startdisp(const void *a, const void *b); - -/* ********************************************************************** - * proxy.c - * - * Proxy functions - * ********************************************************************** */ - -bool SEQ_proxy_rebuild_context(struct Main *bmain, - struct Depsgraph *depsgraph, - struct Scene *scene, - struct Sequence *seq, - struct GSet *file_list, - ListBase *queue); -void SEQ_proxy_rebuild(struct SeqIndexBuildContext *context, - short *stop, - short *do_update, - float *progress); -void SEQ_proxy_rebuild_finish(struct SeqIndexBuildContext *context, bool stop); -void SEQ_proxy_set(struct Sequence *seq, bool value); -bool SEQ_can_use_proxy(struct Sequence *seq, int psize); -int SEQ_rendersize_to_proxysize(int render_size); -double SEQ_rendersize_to_scale_factor(int size); - -/* ********************************************************************** - * image_cache.c - * - * Sequencer memory cache management functions - * ********************************************************************** */ - -void BKE_sequencer_cache_cleanup(struct Scene *scene); -void BKE_sequencer_cache_iterate(struct Scene *scene, - void *userdata, - bool callback_init(void *userdata, size_t item_count), - bool callback_iter(void *userdata, - struct Sequence *seq, - int timeline_frame, - int cache_type, - float cost)); - -/* ********************************************************************** - * prefetch.c - * - * Sequencer frame prefetching - * ********************************************************************** */ - #define SEQ_CACHE_COST_MAX 10.0f -void BKE_sequencer_prefetch_stop_all(void); -void BKE_sequencer_prefetch_stop(struct Scene *scene); -bool BKE_sequencer_prefetch_need_redraw(struct Main *bmain, struct Scene *scene); -/* ********************************************************************** - * sequencer.c - * - * Sequencer editing functions - * ********************************************************************** - */ +/* seq_dupli' flags */ +#define SEQ_DUPE_UNIQUE_NAME (1 << 0) +#define SEQ_DUPE_CONTEXT (1 << 1) +#define SEQ_DUPE_ANIM (1 << 2) +#define SEQ_DUPE_ALL (1 << 3) /* otherwise only selected are copied */ +#define SEQ_DUPE_IS_RECURSIVE_CALL (1 << 4) -/* for transform but also could use elsewhere */ -int BKE_sequence_tx_get_final_left(struct Sequence *seq, bool metaclip); -int BKE_sequence_tx_get_final_right(struct Sequence *seq, bool metaclip); -void BKE_sequence_tx_set_final_left(struct Sequence *seq, int val); -void BKE_sequence_tx_set_final_right(struct Sequence *seq, int val); -void BKE_sequence_tx_handle_xlimits(struct Sequence *seq, int leftflag, int rightflag); -bool BKE_sequence_tx_test(struct Sequence *seq); -bool BKE_sequence_tx_fullupdate_test(struct Sequence *seq); -bool BKE_sequence_single_check(struct Sequence *seq); -void BKE_sequence_single_fix(struct Sequence *seq); -bool BKE_sequence_test_overlap(struct ListBase *seqbasep, struct Sequence *test); -void BKE_sequence_translate(struct Scene *scene, struct Sequence *seq, int delta); -const struct Sequence *BKE_sequencer_foreground_frame_get(const struct Scene *scene, int frame); -struct ListBase *BKE_sequence_seqbase(struct ListBase *seqbase, struct Sequence *seq); -void BKE_sequencer_offset_animdata(struct Scene *scene, struct Sequence *seq, int ofs); -void BKE_sequencer_dupe_animdata(struct Scene *scene, const char *name_src, const char *name_dst); -bool BKE_sequence_base_shuffle_ex(struct ListBase *seqbasep, - struct Sequence *test, - struct Scene *evil_scene, - int channel_delta); -bool BKE_sequence_base_shuffle(struct ListBase *seqbasep, - struct Sequence *test, - struct Scene *evil_scene); -bool BKE_sequence_base_shuffle_time(ListBase *seqbasep, - struct Scene *evil_scene, - ListBase *markers, - const bool use_sync_markers); -bool BKE_sequence_base_isolated_sel_check(struct ListBase *seqbase); -void BKE_sequencer_free_imbuf(struct Scene *scene, struct ListBase *seqbasep, bool for_render); -struct Sequence *BKE_sequence_dupli_recursive(const struct Scene *scene_src, +struct SequencerToolSettings *SEQ_tool_settings_init(void); +void SEQ_tool_settings_free(struct SequencerToolSettings *tool_settings); +eSeqImageFitMethod SEQ_tool_settings_fit_method_get(struct Scene *scene); +void SEQ_tool_settings_fit_method_set(struct Scene *scene, eSeqImageFitMethod fit_method); +struct SequencerToolSettings *SEQ_tool_settings_copy(struct SequencerToolSettings *tool_settings); +struct Editing *SEQ_editing_get(struct Scene *scene, bool alloc); +struct Editing *SEQ_editing_ensure(struct Scene *scene); +void SEQ_editing_free(struct Scene *scene, const bool do_id_user); +struct ListBase *SEQ_active_seqbase_get(const struct Editing *ed); +struct Sequence *SEQ_sequence_alloc(ListBase *lb, int timeline_frame, int machine, int type); +void SEQ_sequence_free(struct Scene *scene, struct Sequence *seq, const bool do_clean_animdata); +void SEQ_offset_animdata(struct Scene *scene, struct Sequence *seq, int ofs); +void SEQ_dupe_animdata(struct Scene *scene, const char *name_src, const char *name_dst); +struct Sequence *SEQ_sequence_dupli_recursive(const struct Scene *scene_src, struct Scene *scene_dst, struct ListBase *new_seq_list, struct Sequence *seq, int dupe_flag); -int BKE_sequence_swap(struct Sequence *seq_a, struct Sequence *seq_b, const char **error_str); -void BKE_sequencer_update_sound_bounds_all(struct Scene *scene); -void BKE_sequencer_update_sound_bounds(struct Scene *scene, struct Sequence *seq); -void BKE_sequencer_update_muting(struct Editing *ed); -void BKE_sequencer_update_sound(struct Scene *scene, struct bSound *sound); -void BKE_sequencer_refresh_sound_length(struct Main *bmain, struct Scene *scene); -void BKE_sequence_base_unique_name_recursive(ListBase *seqbasep, struct Sequence *seq); -void BKE_sequence_base_dupli_recursive(const struct Scene *scene_src, +void SEQ_sequence_base_dupli_recursive(const struct Scene *scene_src, struct Scene *scene_dst, struct ListBase *nseqbase, const struct ListBase *seqbase, int dupe_flag, const int flag); -bool BKE_sequence_is_valid_check(struct Sequence *seq); -struct Sequence *BKE_sequence_get_by_name(struct ListBase *seqbase, - const char *name, - bool recursive); -void BKE_sequencer_flag_for_removal(struct Scene *scene, - struct ListBase *seqbase, - struct Sequence *seq); -void BKE_sequencer_remove_flagged_sequences(struct Scene *scene, struct ListBase *seqbase); - -/* ********************************************************************** - * sequencer.c - * - * Cache invalidation - * ********************************************************************** - */ - -void BKE_sequence_invalidate_cache_raw(struct Scene *scene, struct Sequence *seq); -void BKE_sequence_invalidate_cache_preprocessed(struct Scene *scene, struct Sequence *seq); -void BKE_sequence_invalidate_cache_composite(struct Scene *scene, struct Sequence *seq); -void BKE_sequence_invalidate_dependent(struct Scene *scene, struct Sequence *seq); -void BKE_sequence_invalidate_scene_strips(struct Main *bmain, struct Scene *scene_target); -void BKE_sequence_invalidate_movieclip_strips(struct Main *bmain, struct MovieClip *clip_target); -void BKE_sequence_invalidate_cache_in_range(struct Scene *scene, - struct Sequence *seq, - struct Sequence *range_mask, - int invalidate_types); -void BKE_sequencer_all_free_anim_ibufs(struct Scene *scene, int timeline_frame); - -/* ********************************************************************** - * sequencer.c - * - * Add strips - * ********************************************************************** - */ - -/* api for adding new sequence strips */ -typedef struct SeqLoadInfo { - int start_frame; - int end_frame; - int channel; - int flag; /* use sound, replace sel */ - int type; - int len; /* only for image strips */ - char path[1024]; /* 1024 = FILE_MAX */ - - /* multiview */ - char views_format; - struct Stereo3dFormat *stereo3d_format; - - /* return values */ - char name[64]; - struct Sequence *seq_sound; /* for movie's */ - int tot_success; - int tot_error; -} SeqLoadInfo; - -/* SeqLoadInfo.flag */ -#define SEQ_LOAD_REPLACE_SEL (1 << 0) -#define SEQ_LOAD_FRAME_ADVANCE (1 << 1) -#define SEQ_LOAD_MOVIE_SOUND (1 << 2) -#define SEQ_LOAD_SOUND_CACHE (1 << 3) -#define SEQ_LOAD_SYNC_FPS (1 << 4) -#define SEQ_LOAD_SOUND_MONO (1 << 5) - -/* seq_dupli' flags */ -#define SEQ_DUPE_UNIQUE_NAME (1 << 0) -#define SEQ_DUPE_CONTEXT (1 << 1) -#define SEQ_DUPE_ANIM (1 << 2) -#define SEQ_DUPE_ALL (1 << 3) /* otherwise only selected are copied */ -#define SEQ_DUPE_IS_RECURSIVE_CALL (1 << 4) - -/* use as an api function */ -typedef struct Sequence *(*SeqLoadFn)(struct bContext *, ListBase *, struct SeqLoadInfo *); - -struct Sequence *BKE_sequence_alloc(ListBase *lb, int timeline_frame, int machine, int type); -struct Sequence *BKE_sequencer_add_image_strip(struct bContext *C, - ListBase *seqbasep, - struct SeqLoadInfo *seq_load); -struct Sequence *BKE_sequencer_add_sound_strip(struct bContext *C, - ListBase *seqbasep, - struct SeqLoadInfo *seq_load); -struct Sequence *BKE_sequencer_add_movie_strip(struct bContext *C, - ListBase *seqbasep, - struct SeqLoadInfo *seq_load); - -/* ********************************************************************** - * modifier.c - * - * Modifiers - * ********************************************************************** - */ - -typedef struct SequenceModifierTypeInfo { - /* default name for the modifier */ - char name[64]; /* MAX_NAME */ - - /* DNA structure name used on load/save filed */ - char struct_name[64]; /* MAX_NAME */ - - /* size of modifier data structure, used by allocation */ - int struct_size; - - /* data initialization */ - void (*init_data)(struct SequenceModifierData *smd); - - /* free data used by modifier, - * only modifier-specific data should be freed, modifier descriptor would - * be freed outside of this callback - */ - void (*free_data)(struct SequenceModifierData *smd); - - /* copy data from one modifier to another */ - void (*copy_data)(struct SequenceModifierData *smd, struct SequenceModifierData *target); - - /* apply modifier on a given image buffer */ - void (*apply)(struct SequenceModifierData *smd, struct ImBuf *ibuf, struct ImBuf *mask); -} SequenceModifierTypeInfo; - -const struct SequenceModifierTypeInfo *BKE_sequence_modifier_type_info_get(int type); -struct SequenceModifierData *BKE_sequence_modifier_new(struct Sequence *seq, - const char *name, - int type); -bool BKE_sequence_modifier_remove(struct Sequence *seq, struct SequenceModifierData *smd); -void BKE_sequence_modifier_clear(struct Sequence *seq); -void BKE_sequence_modifier_free(struct SequenceModifierData *smd); -void BKE_sequence_modifier_unique_name(struct Sequence *seq, struct SequenceModifierData *smd); -struct SequenceModifierData *BKE_sequence_modifier_find_by_name(struct Sequence *seq, - const char *name); -struct ImBuf *BKE_sequence_modifier_apply_stack(const SeqRenderData *context, - struct Sequence *seq, - struct ImBuf *ibuf, - int timeline_frame); -void BKE_sequence_modifier_list_copy(struct Sequence *seqn, struct Sequence *seq); -int BKE_sequence_supports_modifiers(struct Sequence *seq); - -void BKE_sequence_modifier_blend_write(struct BlendWriter *writer, struct ListBase *modbase); -void BKE_sequence_modifier_blend_read_data(struct BlendDataReader *reader, struct ListBase *lb); -void BKE_sequence_modifier_blend_read_lib(struct BlendLibReader *reader, - struct Scene *scene, - struct ListBase *lb); - -/* ********************************************************************** - * seqeffects.c - * - * Sequencer effect strip management functions - * ********************************************************************** - */ - -struct SeqEffectHandle { - bool multithreaded; - bool supports_mask; - - /* constructors & destructor */ - /* init is _only_ called on first creation */ - void (*init)(struct Sequence *seq); - - /* number of input strips needed - * (called directly after construction) */ - int (*num_inputs)(void); - - /* load is called first time after readblenfile in - * get_sequence_effect automatically */ - void (*load)(struct Sequence *seqconst); - - /* duplicate */ - void (*copy)(struct Sequence *dst, struct Sequence *src, const int flag); - - /* destruct */ - void (*free)(struct Sequence *seq, const bool do_id_user); - - /* returns: -1: no input needed, - * 0: no early out, - * 1: out = ibuf1, - * 2: out = ibuf2 */ - int (*early_out)(struct Sequence *seq, float facf0, float facf1); - - /* stores the y-range of the effect IPO */ - void (*store_icu_yrange)(struct Sequence *seq, short adrcode, float *ymin, float *ymax); - - /* stores the default facf0 and facf1 if no IPO is present */ - void (*get_default_fac)(struct Sequence *seq, float timeline_frame, float *facf0, float *facf1); - - /* execute the effect - * sequence effects are only required to either support - * float-rects or byte-rects - * (mixed cases are handled one layer up...) */ - - struct ImBuf *(*execute)(const SeqRenderData *context, - struct Sequence *seq, - float timeline_frame, - float facf0, - float facf1, - struct ImBuf *ibuf1, - struct ImBuf *ibuf2, - struct ImBuf *ibuf3); - - struct ImBuf *(*init_execution)(const SeqRenderData *context, - struct ImBuf *ibuf1, - struct ImBuf *ibuf2, - struct ImBuf *ibuf3); - - void (*execute_slice)(const SeqRenderData *context, - struct Sequence *seq, - float timeline_frame, - float facf0, - float facf1, - struct ImBuf *ibuf1, - struct ImBuf *ibuf2, - struct ImBuf *ibuf3, - int start_line, - int total_lines, - struct ImBuf *out); -}; - -struct SeqEffectHandle BKE_sequence_get_effect(struct Sequence *seq); -int BKE_sequence_effect_get_num_inputs(int seq_type); -void BKE_sequencer_text_font_unload(struct TextVars *data, const bool do_id_user); -void BKE_sequencer_text_font_load(struct TextVars *data, const bool do_id_user); - -/* ********************************************************************** - * sequencer.c - * - * Clipboard - * ********************************************************************** - */ - -extern ListBase seqbase_clipboard; -extern int seqbase_clipboard_frame; -void BKE_sequencer_base_clipboard_pointers_store(struct Main *bmain, struct ListBase *seqbase); -void BKE_sequencer_base_clipboard_pointers_restore(struct ListBase *seqbase, struct Main *bmain); -void BKE_sequencer_free_clipboard(void); - -/* ********************************************************************** - * sequencer.c - * - * Depsgraph - * ********************************************************************** - */ - -/* A debug and development function which checks whether sequences have unique UUIDs. - * Errors will be reported to the console. */ -void BKE_sequencer_check_uuids_unique_and_report(const struct Scene *scene); -/* Generate new UUID for the given sequence. */ -void BKE_sequence_session_uuid_generate(struct Sequence *sequence); - -/* ********************************************************************** - * strip_edit.c - * - * Editing functions - * ********************************************************************** - */ - -typedef enum eSeqSplitMethod { - SEQ_SPLIT_SOFT, - SEQ_SPLIT_HARD, -} eSeqSplitMethod; - -struct Sequence *SEQ_edit_strip_split(struct Main *bmain, - struct Scene *scene, - struct ListBase *seqbase, - struct Sequence *seq, - const int timeline_frame, - const eSeqSplitMethod method); #ifdef __cplusplus } diff --git a/source/blender/sequencer/SEQ_sound.h b/source/blender/sequencer/SEQ_sound.h new file mode 100644 index 00000000000..d04aed259fb --- /dev/null +++ b/source/blender/sequencer/SEQ_sound.h @@ -0,0 +1,44 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2004 Blender Foundation. + * All rights reserved. + */ + +#pragma once + +/** \file + * \ingroup sequencer + */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct Scene; +struct Editing; +struct Sequence; +struct bSound; +struct Main; +struct ListBase; + +void SEQ_sound_update_bounds_all(struct Scene *scene); +void SEQ_sound_update_bounds(struct Scene *scene, struct Sequence *seq); +void SEQ_sound_update(struct Scene *scene, struct bSound *sound); +void SEQ_sound_update_length(struct Main *bmain, struct Scene *scene); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/sequencer/SEQ_time.h b/source/blender/sequencer/SEQ_time.h new file mode 100644 index 00000000000..7fb47d42354 --- /dev/null +++ b/source/blender/sequencer/SEQ_time.h @@ -0,0 +1,51 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2004 Blender Foundation. + * All rights reserved. + */ + +#pragma once + +/** \file + * \ingroup sequencer + */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct Scene; +struct Sequence; +struct ListBase; +struct rctf; + +void SEQ_timeline_boundbox(const struct Scene *scene, + const struct ListBase *seqbase, + struct rctf *rect); +float SEQ_time_sequence_get_fps(struct Scene *scene, struct Sequence *seq); +int SEQ_time_find_next_prev_edit(struct Scene *scene, + int timeline_frame, + const short side, + const bool do_skip_mute, + const bool do_center, + const bool do_unselected); +void SEQ_time_update_sequence(struct Scene *scene, struct Sequence *seq); +void SEQ_time_update_sequence_bounds(struct Scene *scene, struct Sequence *seq); +int SEQ_time_cmp_time_startdisp(const void *a, const void *b); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/sequencer/SEQ_transform.h b/source/blender/sequencer/SEQ_transform.h new file mode 100644 index 00000000000..10d9c781dcb --- /dev/null +++ b/source/blender/sequencer/SEQ_transform.h @@ -0,0 +1,63 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2004 Blender Foundation. + * All rights reserved. + */ + +#pragma once + +/** \file + * \ingroup sequencer + */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct Scene; +struct Sequence; +struct ListBase; + +int SEQ_transform_get_left_handle_frame(struct Sequence *seq, bool metaclip); +int SEQ_transform_get_right_handle_frame(struct Sequence *seq, bool metaclip); +void SEQ_transform_set_left_handle_frame(struct Sequence *seq, int val); +void SEQ_transform_set_right_handle_frame(struct Sequence *seq, int val); +void SEQ_transform_handle_xlimits(struct Sequence *seq, int leftflag, int rightflag); +bool SEQ_transform_sequence_can_be_translated(struct Sequence *seq); +bool SEQ_transform_single_image_check(struct Sequence *seq); +void SEQ_transform_fix_single_image_seq_offsets(struct Sequence *seq); +bool SEQ_transform_test_overlap(struct ListBase *seqbasep, struct Sequence *test); +void SEQ_transform_translate_sequence(struct Scene *scene, struct Sequence *seq, int delta); +bool SEQ_transform_seqbase_shuffle_ex(struct ListBase *seqbasep, + struct Sequence *test, + struct Scene *evil_scene, + int channel_delta); +bool SEQ_transform_seqbase_shuffle(struct ListBase *seqbasep, + struct Sequence *test, + struct Scene *evil_scene); +bool SEQ_transform_seqbase_shuffle_time(struct ListBase *seqbasep, + struct Scene *evil_scene, + struct ListBase *markers, + const bool use_sync_markers); +bool SEQ_transform_seqbase_isolated_sel_check(struct ListBase *seqbase); +void SEQ_transform_offset_after_frame(struct Scene *scene, + struct ListBase *seqbase, + const int delta, + const int timeline_frame); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/sequencer/SEQ_util.h b/source/blender/sequencer/SEQ_util.h new file mode 100644 index 00000000000..9dae0a25a37 --- /dev/null +++ b/source/blender/sequencer/SEQ_util.h @@ -0,0 +1,58 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2004 Blender Foundation. + * All rights reserved. + */ + +#pragma once + +/** \file + * \ingroup sequencer + */ + +#include "DNA_scene_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct Scene; +struct Sequence; +struct ListBase; + +void SEQ_set_scale_to_fit(const struct Sequence *seq, + const int image_width, + const int image_height, + const int preview_width, + const int preview_height, + const eSeqImageFitMethod fit_method); +void SEQ_sort(struct Scene *scene); +void SEQ_sequence_base_unique_name_recursive(ListBase *seqbasep, struct Sequence *seq); +const char *SEQ_sequence_give_name(struct Sequence *seq); +ListBase *SEQ_get_seqbase_from_sequence(struct Sequence *seq, int *r_offset); +const struct Sequence *SEQ_get_topmost_sequence(const struct Scene *scene, int frame); +struct ListBase *SEQ_get_seqbase_by_seq(struct ListBase *seqbase, struct Sequence *seq); +struct Sequence *SEQ_sequence_from_strip_elem(ListBase *seqbase, struct StripElem *se); +struct Sequence *SEQ_get_sequence_by_name(struct ListBase *seqbase, + const char *name, + bool recursive); +struct Mask *SEQ_active_mask_get(struct Scene *scene); +void SEQ_alpha_mode_from_file_extension(struct Sequence *seq); +bool SEQ_sequence_has_source(struct Sequence *seq); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/sequencer/SEQ_utils.h b/source/blender/sequencer/SEQ_utils.h new file mode 100644 index 00000000000..417d257ddd7 --- /dev/null +++ b/source/blender/sequencer/SEQ_utils.h @@ -0,0 +1,60 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2004 Blender Foundation. + * All rights reserved. + */ + +#pragma once + +/** \file + * \ingroup sequencer + */ + +#include "DNA_scene_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct Scene; +struct Sequence; +struct ListBase; +struct Mask; +struct StripElem; + +void SEQ_sort(struct Scene *scene); +void SEQ_sequence_base_unique_name_recursive(struct ListBase *seqbasep, struct Sequence *seq); +const char *SEQ_sequence_give_name(struct Sequence *seq); +struct ListBase *SEQ_get_seqbase_from_sequence(struct Sequence *seq, int *r_offset); +const struct Sequence *SEQ_get_topmost_sequence(const struct Scene *scene, int frame); +struct ListBase *SEQ_get_seqbase_by_seq(struct ListBase *seqbase, struct Sequence *seq); +struct Sequence *SEQ_sequence_from_strip_elem(struct ListBase *seqbase, struct StripElem *se); +struct Sequence *SEQ_get_sequence_by_name(struct ListBase *seqbase, + const char *name, + bool recursive); +struct Mask *SEQ_active_mask_get(struct Scene *scene); +void SEQ_alpha_mode_from_file_extension(struct Sequence *seq); +bool SEQ_sequence_has_source(struct Sequence *seq); +void SEQ_set_scale_to_fit(const struct Sequence *seq, + const int image_width, + const int image_height, + const int preview_width, + const int preview_height, + const eSeqImageFitMethod fit_method); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/sequencer/intern/clipboard.c b/source/blender/sequencer/intern/clipboard.c index 7d37dab93dd..29cb749bc99 100644 --- a/source/blender/sequencer/intern/clipboard.c +++ b/source/blender/sequencer/intern/clipboard.c @@ -37,7 +37,7 @@ #include "BKE_scene.h" #include "BKE_sound.h" -#include "SEQ_sequencer.h" +#include "SEQ_clipboard.h" #include "sequencer.h" @@ -56,13 +56,13 @@ ListBase seqbase_clipboard; int seqbase_clipboard_frame; -void BKE_sequencer_base_clipboard_pointers_free(struct ListBase *seqbase); +void seq_clipboard_pointers_free(struct ListBase *seqbase); -void BKE_sequencer_free_clipboard(void) +void SEQ_clipboard_free(void) { Sequence *seq, *nseq; - BKE_sequencer_base_clipboard_pointers_free(&seqbase_clipboard); + seq_clipboard_pointers_free(&seqbase_clipboard); for (seq = seqbase_clipboard.first; seq; seq = nseq) { nseq = seq->next; @@ -153,27 +153,27 @@ static void sequence_clipboard_pointers(Main *bmain, } /* recursive versions of functions above */ -void BKE_sequencer_base_clipboard_pointers_free(ListBase *seqbase) +void seq_clipboard_pointers_free(ListBase *seqbase) { Sequence *seq; for (seq = seqbase->first; seq; seq = seq->next) { sequence_clipboard_pointers(NULL, seq, seqclipboard_ptr_free); - BKE_sequencer_base_clipboard_pointers_free(&seq->seqbase); + seq_clipboard_pointers_free(&seq->seqbase); } } -void BKE_sequencer_base_clipboard_pointers_store(Main *bmain, ListBase *seqbase) +void SEQ_clipboard_pointers_store(Main *bmain, ListBase *seqbase) { Sequence *seq; for (seq = seqbase->first; seq; seq = seq->next) { sequence_clipboard_pointers(bmain, seq, seqclipboard_ptr_store); - BKE_sequencer_base_clipboard_pointers_store(bmain, &seq->seqbase); + SEQ_clipboard_pointers_store(bmain, &seq->seqbase); } } -void BKE_sequencer_base_clipboard_pointers_restore(ListBase *seqbase, Main *bmain) +void SEQ_clipboard_pointers_restore(ListBase *seqbase, Main *bmain) { Sequence *seq; for (seq = seqbase->first; seq; seq = seq->next) { sequence_clipboard_pointers(bmain, seq, seqclipboard_ptr_restore); - BKE_sequencer_base_clipboard_pointers_restore(&seq->seqbase, bmain); + SEQ_clipboard_pointers_restore(&seq->seqbase, bmain); } } diff --git a/source/blender/sequencer/intern/effects.c b/source/blender/sequencer/intern/effects.c index ba16206ce97..e8e80c8da83 100644 --- a/source/blender/sequencer/intern/effects.c +++ b/source/blender/sequencer/intern/effects.c @@ -42,6 +42,7 @@ #include "DNA_scene_types.h" #include "DNA_sequence_types.h" #include "DNA_space_types.h" +#include "DNA_vfont_types.h" #include "BKE_fcurve.h" #include "BKE_lib_id.h" @@ -58,7 +59,10 @@ #include "RE_pipeline.h" -#include "SEQ_sequencer.h" +#include "SEQ_effects.h" +#include "SEQ_proxy.h" +#include "SEQ_render.h" +#include "SEQ_utils.h" #include "BLF_api.h" @@ -2987,7 +2991,7 @@ static ImBuf *do_multicam(const SeqRenderData *context, if (!ed) { return NULL; } - seqbasep = BKE_sequence_seqbase(&ed->seqbase, seq); + seqbasep = SEQ_get_seqbase_by_seq(&ed->seqbase, seq); if (!seqbasep) { return NULL; } @@ -3018,7 +3022,7 @@ static ImBuf *do_adjustment_impl(const SeqRenderData *context, Sequence *seq, fl ed = context->scene->ed; - seqbasep = BKE_sequence_seqbase(&ed->seqbase, seq); + seqbasep = SEQ_get_seqbase_by_seq(&ed->seqbase, seq); if (seq->machine > 1) { i = seq_render_give_ibuf_seqbase(context, timeline_frame, seq->machine - 1, seqbasep); @@ -3032,7 +3036,7 @@ static ImBuf *do_adjustment_impl(const SeqRenderData *context, Sequence *seq, fl if (!i) { Sequence *meta; - meta = BKE_sequence_metastrip(&ed->seqbase, NULL, seq); + meta = seq_find_metastrip_by_sequence(&ed->seqbase, NULL, seq); if (meta) { i = do_adjustment_impl(context, meta, timeline_frame); @@ -3128,7 +3132,7 @@ static void store_icu_yrange_speed(Sequence *seq, short UNUSED(adrcode), float * SpeedControlVars *v = (SpeedControlVars *)seq->effectdata; /* if not already done, load / initialize data */ - BKE_sequence_get_effect(seq); + SEQ_effect_handle_get(seq); if ((v->flags & SEQ_SPEED_INTEGRATE) != 0) { *ymin = -100.0; @@ -3146,7 +3150,7 @@ static void store_icu_yrange_speed(Sequence *seq, short UNUSED(adrcode), float * } } -void BKE_sequence_effect_speed_rebuild_map(Scene *scene, Sequence *seq, bool force) +void seq_effect_speed_rebuild_map(Scene *scene, Sequence *seq, bool force) { int timeline_frame; float fallback_fac = 1.0f; @@ -3155,7 +3159,7 @@ void BKE_sequence_effect_speed_rebuild_map(Scene *scene, Sequence *seq, bool for int flags = v->flags; /* if not already done, load / initialize data */ - BKE_sequence_get_effect(seq); + SEQ_effect_handle_get(seq); if ((force == false) && (seq->len == v->length) && (v->frameMap != NULL)) { return; @@ -3251,14 +3255,14 @@ void BKE_sequence_effect_speed_rebuild_map(Scene *scene, Sequence *seq, bool for } /* Override timeline_frame when rendering speed effect input. */ -float BKE_sequencer_speed_effect_target_frame_get(const SeqRenderData *context, - Sequence *seq, - float timeline_frame, - int input) +float seq_speed_effect_target_frame_get(const SeqRenderData *context, + Sequence *seq, + float timeline_frame, + int input) { int frame_index = seq_give_frame_index(seq, timeline_frame); SpeedControlVars *s = (SpeedControlVars *)seq->effectdata; - BKE_sequence_effect_speed_rebuild_map(context->scene, seq, false); + seq_effect_speed_rebuild_map(context->scene, seq, false); /* No interpolation. */ if ((s->flags & SEQ_SPEED_USE_INTERPOLATION) == 0) { @@ -3803,7 +3807,7 @@ static void init_text_effect(Sequence *seq) data->align_y = SEQ_TEXT_ALIGN_Y_BOTTOM; } -void BKE_sequencer_text_font_unload(TextVars *data, const bool do_id_user) +void SEQ_effect_text_font_unload(TextVars *data, const bool do_id_user) { if (data) { /* Unlink the VFont */ @@ -3819,7 +3823,7 @@ void BKE_sequencer_text_font_unload(TextVars *data, const bool do_id_user) } } -void BKE_sequencer_text_font_load(TextVars *data, const bool do_id_user) +void SEQ_effect_text_font_load(TextVars *data, const bool do_id_user) { if (data->text_font != NULL) { if (do_id_user) { @@ -3838,7 +3842,7 @@ void BKE_sequencer_text_font_load(TextVars *data, const bool do_id_user) static void free_text_effect(Sequence *seq, const bool do_id_user) { TextVars *data = seq->effectdata; - BKE_sequencer_text_font_unload(data, do_id_user); + SEQ_effect_text_font_unload(data, do_id_user); if (data) { MEM_freeN(data); @@ -3849,7 +3853,7 @@ static void free_text_effect(Sequence *seq, const bool do_id_user) static void load_text_effect(Sequence *seq) { TextVars *data = seq->effectdata; - BKE_sequencer_text_font_load(data, false); + SEQ_effect_text_font_load(data, false); } static void copy_text_effect(Sequence *dst, Sequence *src, const int flag) @@ -3858,7 +3862,7 @@ static void copy_text_effect(Sequence *dst, Sequence *src, const int flag) TextVars *data = dst->effectdata; data->text_blf_id = -1; - BKE_sequencer_text_font_load(data, (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0); + SEQ_effect_text_font_load(data, (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0); } static int num_inputs_text(void) @@ -4274,7 +4278,7 @@ static struct SeqEffectHandle get_sequence_effect_impl(int seq_type) return rval; } -struct SeqEffectHandle BKE_sequence_get_effect(Sequence *seq) +struct SeqEffectHandle SEQ_effect_handle_get(Sequence *seq) { struct SeqEffectHandle rval = {false, false, NULL}; @@ -4289,7 +4293,7 @@ struct SeqEffectHandle BKE_sequence_get_effect(Sequence *seq) return rval; } -struct SeqEffectHandle BKE_sequence_get_blend(Sequence *seq) +struct SeqEffectHandle seq_effect_get_sequence_blend(Sequence *seq) { struct SeqEffectHandle rval = {false, false, NULL}; @@ -4311,7 +4315,7 @@ struct SeqEffectHandle BKE_sequence_get_blend(Sequence *seq) return rval; } -int BKE_sequence_effect_get_num_inputs(int seq_type) +int SEQ_effect_get_num_inputs(int seq_type) { struct SeqEffectHandle rval = get_sequence_effect_impl(seq_type); diff --git a/source/blender/sequencer/intern/effects.h b/source/blender/sequencer/intern/effects.h index 58e0a97d4c5..1bce4f324c3 100644 --- a/source/blender/sequencer/intern/effects.h +++ b/source/blender/sequencer/intern/effects.h @@ -28,8 +28,8 @@ extern "C" { #endif struct Scene; -struct Sequence; struct SeqRenderData; +struct Sequence; /* ********************************************************************** * sequencer.c @@ -38,12 +38,12 @@ struct SeqRenderData; * ********************************************************************** */ -struct SeqEffectHandle BKE_sequence_get_blend(struct Sequence *seq); -void BKE_sequence_effect_speed_rebuild_map(struct Scene *scene, struct Sequence *seq, bool force); -float BKE_sequencer_speed_effect_target_frame_get(const struct SeqRenderData *context, - struct Sequence *seq, - float timeline_frame, - int input); +struct SeqEffectHandle seq_effect_get_sequence_blend(struct Sequence *seq); +void seq_effect_speed_rebuild_map(struct Scene *scene, struct Sequence *seq, bool force); +float seq_speed_effect_target_frame_get(const struct SeqRenderData *context, + struct Sequence *seq, + float timeline_frame, + int input); #ifdef __cplusplus } diff --git a/source/blender/sequencer/intern/image_cache.c b/source/blender/sequencer/intern/image_cache.c index d515a13cdee..40ad70cf9a0 100644 --- a/source/blender/sequencer/intern/image_cache.c +++ b/source/blender/sequencer/intern/image_cache.c @@ -48,6 +48,9 @@ #include "BKE_main.h" #include "BKE_scene.h" +#include "SEQ_prefetch.h" +#include "SEQ_relations.h" +#include "SEQ_render.h" #include "SEQ_sequencer.h" #include "image_cache.h" @@ -144,7 +147,6 @@ typedef struct SeqCache { struct BLI_mempool *keys_pool; struct BLI_mempool *items_pool; struct SeqCacheKey *last_key; - size_t memory_used; SeqDiskCache *disk_cache; } SeqCache; @@ -793,17 +795,15 @@ static void seq_cache_keyfree(void *val) static void seq_cache_valfree(void *val) { SeqCacheItem *item = (SeqCacheItem *)val; - SeqCache *cache = item->cache_owner; if (item->ibuf) { - cache->memory_used -= IMB_get_size_in_memory(item->ibuf); IMB_freeImBuf(item->ibuf); } BLI_mempool_free(item->cache_owner->items_pool, item); } -static void seq_cache_put(SeqCache *cache, SeqCacheKey *key, ImBuf *ibuf) +static void seq_cache_put_ex(SeqCache *cache, SeqCacheKey *key, ImBuf *ibuf) { SeqCacheItem *item; item = BLI_mempool_alloc(cache->items_pool); @@ -813,11 +813,10 @@ static void seq_cache_put(SeqCache *cache, SeqCacheKey *key, ImBuf *ibuf) if (BLI_ghash_reinsert(cache->hash, key, item, seq_cache_keyfree, seq_cache_valfree)) { IMB_refImBuf(ibuf); cache->last_key = key; - cache->memory_used += IMB_get_size_in_memory(ibuf); } } -static ImBuf *seq_cache_get(SeqCache *cache, SeqCacheKey *key) +static ImBuf *seq_cache_get_ex(SeqCache *cache, SeqCacheKey *key) { SeqCacheItem *item = BLI_ghash_lookup(cache->hash, key); @@ -856,10 +855,9 @@ static SeqCacheKey *seq_cache_choose_key(Scene *scene, SeqCacheKey *lkey, SeqCac * We could use temp cache as a shield and later make it a non-temporary entry, * but it is not worth of increasing system complexity. */ - if (scene->ed->cache_flag & SEQ_CACHE_PREFETCH_ENABLE && - BKE_sequencer_prefetch_job_is_running(scene)) { + if (scene->ed->cache_flag & SEQ_CACHE_PREFETCH_ENABLE && seq_prefetch_job_is_running(scene)) { int pfjob_start, pfjob_end; - BKE_sequencer_prefetch_get_time_range(scene, &pfjob_start, &pfjob_end); + seq_prefetch_get_time_range(scene, &pfjob_start, &pfjob_end); if (lkey) { if (lkey->timeline_frame < pfjob_start || lkey->timeline_frame > pfjob_end) { @@ -940,7 +938,6 @@ static SeqCacheKey *seq_cache_get_item_for_removal(Scene *scene) GHashIterator gh_iter; BLI_ghashIterator_init(&gh_iter, cache->hash); int total_count = 0; - int cheap_count = 0; while (!BLI_ghashIterator_done(&gh_iter)) { key = BLI_ghashIterator_getKey(&gh_iter); @@ -961,25 +958,22 @@ static SeqCacheKey *seq_cache_get_item_for_removal(Scene *scene) total_count++; - if (key->cost <= scene->ed->recycle_max_cost) { - cheap_count++; - if (lkey) { - if (key->timeline_frame < lkey->timeline_frame) { - lkey = key; - } - } - else { + if (lkey) { + if (key->timeline_frame < lkey->timeline_frame) { lkey = key; } - if (rkey) { - if (key->timeline_frame > rkey->timeline_frame) { - rkey = key; - } - } - else { + } + else { + lkey = key; + } + if (rkey) { + if (key->timeline_frame > rkey->timeline_frame) { rkey = key; } } + else { + rkey = key; + } } finalkey = seq_cache_choose_key(scene, lkey, rkey); @@ -990,9 +984,8 @@ static SeqCacheKey *seq_cache_get_item_for_removal(Scene *scene) /* Find only "base" keys. * Sources(other types) for a frame must be freed all at once. */ -bool BKE_sequencer_cache_recycle_item(Scene *scene) +bool seq_cache_recycle_item(Scene *scene) { - size_t memory_total = seq_cache_get_mem_total(); SeqCache *cache = seq_cache_get_from_scene(scene); if (!cache) { return false; @@ -1000,7 +993,7 @@ bool BKE_sequencer_cache_recycle_item(Scene *scene) seq_cache_lock(scene); - while (cache->memory_used > memory_total) { + while (seq_cache_is_full()) { SeqCacheKey *finalkey = seq_cache_get_item_for_removal(scene); if (finalkey) { @@ -1083,7 +1076,7 @@ static void seq_cache_create(Main *bmain, Scene *scene) /* ***************************** API ****************************** */ -void BKE_sequencer_cache_free_temp_cache(Scene *scene, short id, int timeline_frame) +void seq_cache_free_temp_cache(Scene *scene, short id, int timeline_frame) { SeqCache *cache = seq_cache_get_from_scene(scene); if (!cache) { @@ -1111,7 +1104,7 @@ void BKE_sequencer_cache_free_temp_cache(Scene *scene, short id, int timeline_fr seq_cache_unlock(scene); } -void BKE_sequencer_cache_destruct(Scene *scene) +void seq_cache_destruct(Scene *scene) { SeqCache *cache = seq_cache_get_from_scene(scene); if (!cache) { @@ -1133,15 +1126,15 @@ void BKE_sequencer_cache_destruct(Scene *scene) scene->ed->cache = NULL; } -void BKE_sequencer_cache_cleanup_all(Main *bmain) +void seq_cache_cleanup_all(Main *bmain) { for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) { - BKE_sequencer_cache_cleanup(scene); + SEQ_cache_cleanup(scene); } } -void BKE_sequencer_cache_cleanup(Scene *scene) +void SEQ_cache_cleanup(Scene *scene) { - BKE_sequencer_prefetch_stop(scene); + SEQ_prefetch_stop(scene); SeqCache *cache = seq_cache_get_from_scene(scene); if (!cache) { @@ -1162,11 +1155,11 @@ void BKE_sequencer_cache_cleanup(Scene *scene) seq_cache_unlock(scene); } -void BKE_sequencer_cache_cleanup_sequence(Scene *scene, - Sequence *seq, - Sequence *seq_changed, - int invalidate_types, - bool force_seq_changed_range) +void seq_cache_cleanup_sequence(Scene *scene, + Sequence *seq, + Sequence *seq_changed, + int invalidate_types, + bool force_seq_changed_range) { SeqCache *cache = seq_cache_get_from_scene(scene); if (!cache) { @@ -1226,11 +1219,11 @@ void BKE_sequencer_cache_cleanup_sequence(Scene *scene, seq_cache_unlock(scene); } -struct ImBuf *BKE_sequencer_cache_get(const SeqRenderData *context, - Sequence *seq, - float timeline_frame, - int type, - bool skip_disk_cache) +struct ImBuf *seq_cache_get(const SeqRenderData *context, + Sequence *seq, + float timeline_frame, + int type, + bool skip_disk_cache) { if (context->skip_cache || context->is_proxy_render || !seq) { @@ -1240,9 +1233,9 @@ struct ImBuf *BKE_sequencer_cache_get(const SeqRenderData *context, Scene *scene = context->scene; if (context->is_prefetch_render) { - context = BKE_sequencer_prefetch_get_original_context(context); + context = seq_prefetch_get_original_context(context); scene = context->scene; - seq = BKE_sequencer_prefetch_get_original_sequence(seq, scene); + seq = seq_prefetch_get_original_sequence(seq, scene); } if (!seq) { @@ -1265,7 +1258,7 @@ struct ImBuf *BKE_sequencer_cache_get(const SeqRenderData *context, key.frame_index = seq_cache_timeline_frame_to_frame_index(seq, timeline_frame, type); key.type = type; - ibuf = seq_cache_get(cache, &key); + ibuf = seq_cache_get_ex(cache, &key); } seq_cache_unlock(scene); @@ -1284,10 +1277,10 @@ struct ImBuf *BKE_sequencer_cache_get(const SeqRenderData *context, BLI_mutex_unlock(&cache->disk_cache->read_write_mutex); if (ibuf) { if (key.type == SEQ_CACHE_STORE_FINAL_OUT) { - BKE_sequencer_cache_put_if_possible(context, seq, timeline_frame, type, ibuf, 0.0f, true); + seq_cache_put_if_possible(context, seq, timeline_frame, type, ibuf, true); } else { - BKE_sequencer_cache_put(context, seq, timeline_frame, type, ibuf, 0.0f, true); + seq_cache_put(context, seq, timeline_frame, type, ibuf, true); } } } @@ -1295,28 +1288,27 @@ struct ImBuf *BKE_sequencer_cache_get(const SeqRenderData *context, return ibuf; } -bool BKE_sequencer_cache_put_if_possible(const SeqRenderData *context, - Sequence *seq, - float timeline_frame, - int type, - ImBuf *ibuf, - float cost, - bool skip_disk_cache) +bool seq_cache_put_if_possible(const SeqRenderData *context, + Sequence *seq, + float timeline_frame, + int type, + ImBuf *ibuf, + bool skip_disk_cache) { Scene *scene = context->scene; if (context->is_prefetch_render) { - context = BKE_sequencer_prefetch_get_original_context(context); + context = seq_prefetch_get_original_context(context); scene = context->scene; - seq = BKE_sequencer_prefetch_get_original_sequence(seq, scene); + seq = seq_prefetch_get_original_sequence(seq, scene); } if (!seq) { return false; } - if (BKE_sequencer_cache_recycle_item(scene)) { - BKE_sequencer_cache_put(context, seq, timeline_frame, type, ibuf, cost, skip_disk_cache); + if (seq_cache_recycle_item(scene)) { + seq_cache_put(context, seq, timeline_frame, type, ibuf, skip_disk_cache); return true; } @@ -1325,13 +1317,12 @@ bool BKE_sequencer_cache_put_if_possible(const SeqRenderData *context, return false; } -void BKE_sequencer_cache_put(const SeqRenderData *context, - Sequence *seq, - float timeline_frame, - int type, - ImBuf *i, - float cost, - bool skip_disk_cache) +void seq_cache_put(const SeqRenderData *context, + Sequence *seq, + float timeline_frame, + int type, + ImBuf *i, + bool skip_disk_cache) { if (i == NULL || context->skip_cache || context->is_proxy_render || !seq) { return; @@ -1340,14 +1331,14 @@ void BKE_sequencer_cache_put(const SeqRenderData *context, Scene *scene = context->scene; if (context->is_prefetch_render) { - context = BKE_sequencer_prefetch_get_original_context(context); + context = seq_prefetch_get_original_context(context); scene = context->scene; - seq = BKE_sequencer_prefetch_get_original_sequence(seq, scene); + seq = seq_prefetch_get_original_sequence(seq, scene); BLI_assert(seq != NULL); } /* Prevent reinserting, it breaks cache key linking. */ - ImBuf *test = BKE_sequencer_cache_get(context, seq, timeline_frame, type, true); + ImBuf *test = seq_cache_get(context, seq, timeline_frame, type, true); if (test) { IMB_freeImBuf(test); return; @@ -1373,10 +1364,6 @@ void BKE_sequencer_cache_put(const SeqRenderData *context, flag = scene->ed->cache_flag; } - if (cost > SEQ_CACHE_COST_MAX) { - cost = SEQ_CACHE_COST_MAX; - } - SeqCacheKey *key; key = BLI_mempool_alloc(cache->keys_pool); key->cache_owner = cache; @@ -1385,7 +1372,6 @@ void BKE_sequencer_cache_put(const SeqRenderData *context, key->frame_index = seq_cache_timeline_frame_to_frame_index(seq, timeline_frame, type); key->timeline_frame = timeline_frame; key->type = type; - key->cost = cost; key->link_prev = NULL; key->link_next = NULL; key->is_temp_cache = true; @@ -1398,7 +1384,7 @@ void BKE_sequencer_cache_put(const SeqRenderData *context, } SeqCacheKey *temp_last_key = cache->last_key; - seq_cache_put(cache, key, i); + seq_cache_put_ex(cache, key, i); /* Restore pointer to previous item as this one will be freed when stack is rendered. */ if (key->is_temp_cache) { @@ -1433,14 +1419,11 @@ void BKE_sequencer_cache_put(const SeqRenderData *context, } } -void BKE_sequencer_cache_iterate(struct Scene *scene, - void *userdata, - bool callback_init(void *userdata, size_t item_count), - bool callback_iter(void *userdata, - struct Sequence *seq, - int timeline_frame, - int cache_type, - float cost)) +void SEQ_cache_iterate( + struct Scene *scene, + void *userdata, + bool callback_init(void *userdata, size_t item_count), + bool callback_iter(void *userdata, struct Sequence *seq, int timeline_frame, int cache_type)) { SeqCache *cache = seq_cache_get_from_scene(scene); if (!cache) { @@ -1457,20 +1440,14 @@ void BKE_sequencer_cache_iterate(struct Scene *scene, SeqCacheKey *key = BLI_ghashIterator_getKey(&gh_iter); BLI_ghashIterator_step(&gh_iter); - interrupt = callback_iter(userdata, key->seq, key->timeline_frame, key->type, key->cost); + interrupt = callback_iter(userdata, key->seq, key->timeline_frame, key->type); } cache->last_key = NULL; seq_cache_unlock(scene); } -bool BKE_sequencer_cache_is_full(Scene *scene) +bool seq_cache_is_full(void) { - size_t memory_total = seq_cache_get_mem_total(); - SeqCache *cache = seq_cache_get_from_scene(scene); - if (!cache) { - return false; - } - - return memory_total < cache->memory_used; + return seq_cache_get_mem_total() < MEM_get_memory_in_use(); } diff --git a/source/blender/sequencer/intern/image_cache.h b/source/blender/sequencer/intern/image_cache.h index 0fcf0548628..41e8c4d1d48 100644 --- a/source/blender/sequencer/intern/image_cache.h +++ b/source/blender/sequencer/intern/image_cache.h @@ -30,42 +30,40 @@ extern "C" { struct ImBuf; struct Main; struct Scene; -struct Sequence; struct SeqRenderData; +struct Sequence; #ifdef __cplusplus } #endif -struct ImBuf *BKE_sequencer_cache_get(const struct SeqRenderData *context, - struct Sequence *seq, - float timeline_frame, - int type, - bool skip_disk_cache); -void BKE_sequencer_cache_put(const struct SeqRenderData *context, - struct Sequence *seq, - float timeline_frame, - int type, - struct ImBuf *i, - float cost, - bool skip_disk_cache); -bool BKE_sequencer_cache_put_if_possible(const struct SeqRenderData *context, - struct Sequence *seq, - float timeline_frame, - int type, - struct ImBuf *nval, - float cost, - bool skip_disk_cache); -bool BKE_sequencer_cache_recycle_item(struct Scene *scene); -void BKE_sequencer_cache_free_temp_cache(struct Scene *scene, short id, int timeline_frame); -void BKE_sequencer_cache_destruct(struct Scene *scene); -void BKE_sequencer_cache_cleanup_all(struct Main *bmain); -void BKE_sequencer_cache_cleanup_sequence(struct Scene *scene, - struct Sequence *seq, - struct Sequence *seq_changed, - int invalidate_types, - bool force_seq_changed_range); -bool BKE_sequencer_cache_is_full(struct Scene *scene); +struct ImBuf *seq_cache_get(const struct SeqRenderData *context, + struct Sequence *seq, + float timeline_frame, + int type, + bool skip_disk_cache); +void seq_cache_put(const struct SeqRenderData *context, + struct Sequence *seq, + float timeline_frame, + int type, + struct ImBuf *i, + bool skip_disk_cache); +bool seq_cache_put_if_possible(const struct SeqRenderData *context, + struct Sequence *seq, + float timeline_frame, + int type, + struct ImBuf *nval, + bool skip_disk_cache); +bool seq_cache_recycle_item(struct Scene *scene); +void seq_cache_free_temp_cache(struct Scene *scene, short id, int timeline_frame); +void seq_cache_destruct(struct Scene *scene); +void seq_cache_cleanup_all(struct Main *bmain); +void seq_cache_cleanup_sequence(struct Scene *scene, + struct Sequence *seq, + struct Sequence *seq_changed, + int invalidate_types, + bool force_seq_changed_range); +bool seq_cache_is_full(void); #ifdef __cplusplus } diff --git a/source/blender/sequencer/intern/iterator.c b/source/blender/sequencer/intern/iterator.c index fe6f4184ab1..bb4982d1468 100644 --- a/source/blender/sequencer/intern/iterator.c +++ b/source/blender/sequencer/intern/iterator.c @@ -35,7 +35,7 @@ #include "BKE_scene.h" -#include "SEQ_sequencer.h" +#include "SEQ_iterator.h" /* ************************* iterator ************************** */ /* *************** (replaces old WHILE_SEQ) ********************* */ @@ -108,7 +108,7 @@ static void seq_array(Editing *ed, } } -void BKE_sequence_iterator_begin(Editing *ed, SeqIterator *iter, const bool use_current_sequences) +void SEQ_iterator_begin(Editing *ed, SeqIterator *iter, const bool use_current_sequences) { memset(iter, 0, sizeof(*iter)); seq_array(ed, &iter->array, &iter->tot, use_current_sequences); @@ -120,7 +120,7 @@ void BKE_sequence_iterator_begin(Editing *ed, SeqIterator *iter, const bool use_ } } -void BKE_sequence_iterator_next(SeqIterator *iter) +void SEQ_iterator_next(SeqIterator *iter) { if (++iter->cur < iter->tot) { iter->seq = iter->array[iter->cur]; @@ -130,7 +130,7 @@ void BKE_sequence_iterator_next(SeqIterator *iter) } } -void BKE_sequence_iterator_end(SeqIterator *iter) +void SEQ_iterator_end(SeqIterator *iter) { if (iter->array) { MEM_freeN(iter->array); @@ -139,20 +139,20 @@ void BKE_sequence_iterator_end(SeqIterator *iter) iter->valid = 0; } -int BKE_sequencer_base_recursive_apply(ListBase *seqbase, - int (*apply_fn)(Sequence *seq, void *), - void *arg) +int SEQ_iterator_seqbase_recursive_apply(ListBase *seqbase, + int (*apply_fn)(Sequence *seq, void *), + void *arg) { Sequence *iseq; for (iseq = seqbase->first; iseq; iseq = iseq->next) { - if (BKE_sequencer_recursive_apply(iseq, apply_fn, arg) == -1) { + if (SEQ_iterator_recursive_apply(iseq, apply_fn, arg) == -1) { return -1; /* bail out */ } } return 1; } -int BKE_sequencer_recursive_apply(Sequence *seq, int (*apply_fn)(Sequence *, void *), void *arg) +int SEQ_iterator_recursive_apply(Sequence *seq, int (*apply_fn)(Sequence *, void *), void *arg) { int ret = apply_fn(seq, arg); @@ -161,7 +161,7 @@ int BKE_sequencer_recursive_apply(Sequence *seq, int (*apply_fn)(Sequence *, voi } if (ret && seq->seqbase.first) { - ret = BKE_sequencer_base_recursive_apply(&seq->seqbase, apply_fn, arg); + ret = SEQ_iterator_seqbase_recursive_apply(&seq->seqbase, apply_fn, arg); } return ret; diff --git a/source/blender/sequencer/intern/modifier.c b/source/blender/sequencer/intern/modifier.c index 2c37ecf1910..b6f56025e6b 100644 --- a/source/blender/sequencer/intern/modifier.c +++ b/source/blender/sequencer/intern/modifier.c @@ -44,7 +44,8 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" -#include "SEQ_sequencer.h" +#include "SEQ_modifier.h" +#include "SEQ_render.h" #include "BLO_read_write.h" @@ -1316,7 +1317,7 @@ static void sequence_modifier_type_info_init(void) #undef INIT_TYPE } -const SequenceModifierTypeInfo *BKE_sequence_modifier_type_info_get(int type) +const SequenceModifierTypeInfo *SEQ_modifier_type_info_get(int type) { if (!modifierTypesInit) { sequence_modifier_type_info_init(); @@ -1326,10 +1327,10 @@ const SequenceModifierTypeInfo *BKE_sequence_modifier_type_info_get(int type) return modifiersTypes[type]; } -SequenceModifierData *BKE_sequence_modifier_new(Sequence *seq, const char *name, int type) +SequenceModifierData *SEQ_modifier_new(Sequence *seq, const char *name, int type) { SequenceModifierData *smd; - const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(type); + const SequenceModifierTypeInfo *smti = SEQ_modifier_type_info_get(type); smd = MEM_callocN(smti->struct_size, "sequence modifier"); @@ -1345,7 +1346,7 @@ SequenceModifierData *BKE_sequence_modifier_new(Sequence *seq, const char *name, BLI_addtail(&seq->modifiers, smd); - BKE_sequence_modifier_unique_name(seq, smd); + SEQ_modifier_unique_name(seq, smd); if (smti->init_data) { smti->init_data(smd); @@ -1354,33 +1355,33 @@ SequenceModifierData *BKE_sequence_modifier_new(Sequence *seq, const char *name, return smd; } -bool BKE_sequence_modifier_remove(Sequence *seq, SequenceModifierData *smd) +bool SEQ_modifier_remove(Sequence *seq, SequenceModifierData *smd) { if (BLI_findindex(&seq->modifiers, smd) == -1) { return false; } BLI_remlink(&seq->modifiers, smd); - BKE_sequence_modifier_free(smd); + SEQ_modifier_free(smd); return true; } -void BKE_sequence_modifier_clear(Sequence *seq) +void SEQ_modifier_clear(Sequence *seq) { SequenceModifierData *smd, *smd_next; for (smd = seq->modifiers.first; smd; smd = smd_next) { smd_next = smd->next; - BKE_sequence_modifier_free(smd); + SEQ_modifier_free(smd); } BLI_listbase_clear(&seq->modifiers); } -void BKE_sequence_modifier_free(SequenceModifierData *smd) +void SEQ_modifier_free(SequenceModifierData *smd) { - const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type); + const SequenceModifierTypeInfo *smti = SEQ_modifier_type_info_get(smd->type); if (smti && smti->free_data) { smti->free_data(smd); @@ -1389,9 +1390,9 @@ void BKE_sequence_modifier_free(SequenceModifierData *smd) MEM_freeN(smd); } -void BKE_sequence_modifier_unique_name(Sequence *seq, SequenceModifierData *smd) +void SEQ_modifier_unique_name(Sequence *seq, SequenceModifierData *smd) { - const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type); + const SequenceModifierTypeInfo *smti = SEQ_modifier_type_info_get(smd->type); BLI_uniquename(&seq->modifiers, smd, @@ -1401,15 +1402,15 @@ void BKE_sequence_modifier_unique_name(Sequence *seq, SequenceModifierData *smd) sizeof(smd->name)); } -SequenceModifierData *BKE_sequence_modifier_find_by_name(Sequence *seq, const char *name) +SequenceModifierData *SEQ_modifier_find_by_name(Sequence *seq, const char *name) { return BLI_findstring(&(seq->modifiers), name, offsetof(SequenceModifierData, name)); } -ImBuf *BKE_sequence_modifier_apply_stack(const SeqRenderData *context, - Sequence *seq, - ImBuf *ibuf, - int timeline_frame) +ImBuf *SEQ_modifier_apply_stack(const SeqRenderData *context, + Sequence *seq, + ImBuf *ibuf, + int timeline_frame) { SequenceModifierData *smd; ImBuf *processed_ibuf = ibuf; @@ -1420,7 +1421,7 @@ ImBuf *BKE_sequence_modifier_apply_stack(const SeqRenderData *context, } for (smd = seq->modifiers.first; smd; smd = smd->next) { - const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type); + const SequenceModifierTypeInfo *smti = SEQ_modifier_type_info_get(smd->type); /* could happen if modifier is being removed or not exists in current version of blender */ if (!smti) { @@ -1463,13 +1464,13 @@ ImBuf *BKE_sequence_modifier_apply_stack(const SeqRenderData *context, return processed_ibuf; } -void BKE_sequence_modifier_list_copy(Sequence *seqn, Sequence *seq) +void SEQ_modifier_list_copy(Sequence *seqn, Sequence *seq) { SequenceModifierData *smd; for (smd = seq->modifiers.first; smd; smd = smd->next) { SequenceModifierData *smdn; - const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type); + const SequenceModifierTypeInfo *smti = SEQ_modifier_type_info_get(smd->type); smdn = MEM_dupallocN(smd); @@ -1482,7 +1483,7 @@ void BKE_sequence_modifier_list_copy(Sequence *seqn, Sequence *seq) } } -int BKE_sequence_supports_modifiers(Sequence *seq) +int SEQ_sequence_supports_modifiers(Sequence *seq) { return !ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD); } @@ -1493,10 +1494,10 @@ int BKE_sequence_supports_modifiers(Sequence *seq) /** \name .blend File I/O * \{ */ -void BKE_sequence_modifier_blend_write(BlendWriter *writer, ListBase *modbase) +void SEQ_modifier_blend_write(BlendWriter *writer, ListBase *modbase) { LISTBASE_FOREACH (SequenceModifierData *, smd, modbase) { - const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type); + const SequenceModifierTypeInfo *smti = SEQ_modifier_type_info_get(smd->type); if (smti) { BLO_write_struct_by_name(writer, smti->struct_name, smd); @@ -1518,7 +1519,7 @@ void BKE_sequence_modifier_blend_write(BlendWriter *writer, ListBase *modbase) } } -void BKE_sequence_modifier_blend_read_data(BlendDataReader *reader, ListBase *lb) +void SEQ_modifier_blend_read_data(BlendDataReader *reader, ListBase *lb) { BLO_read_list(reader, lb); @@ -1540,7 +1541,7 @@ void BKE_sequence_modifier_blend_read_data(BlendDataReader *reader, ListBase *lb } } -void BKE_sequence_modifier_blend_read_lib(BlendLibReader *reader, Scene *scene, ListBase *lb) +void SEQ_modifier_blend_read_lib(BlendLibReader *reader, Scene *scene, ListBase *lb) { LISTBASE_FOREACH (SequenceModifierData *, smd, lb) { if (smd->mask_id) { diff --git a/source/blender/sequencer/intern/multiview.h b/source/blender/sequencer/intern/multiview.h index e1f998d18e2..bbc66c6f84c 100644 --- a/source/blender/sequencer/intern/multiview.h +++ b/source/blender/sequencer/intern/multiview.h @@ -27,14 +27,7 @@ extern "C" { #endif -struct Editing; -struct ImBuf; -struct Main; -struct Mask; struct Scene; -struct Sequence; -struct StripColorBalance; -struct StripElem; /* ********************************************************************** * sequencer.c diff --git a/source/blender/sequencer/intern/prefetch.c b/source/blender/sequencer/intern/prefetch.c index 98b83651ffc..55df17c01f9 100644 --- a/source/blender/sequencer/intern/prefetch.c +++ b/source/blender/sequencer/intern/prefetch.c @@ -53,7 +53,8 @@ #include "DEG_depsgraph_debug.h" #include "DEG_depsgraph_query.h" -#include "SEQ_sequencer.h" +#include "SEQ_prefetch.h" +#include "SEQ_render.h" #include "image_cache.h" #include "prefetch.h" @@ -118,7 +119,7 @@ static PrefetchJob *seq_prefetch_job_get(Scene *scene) return NULL; } -bool BKE_sequencer_prefetch_job_is_running(Scene *scene) +bool seq_prefetch_job_is_running(Scene *scene) { PrefetchJob *pfjob = seq_prefetch_job_get(scene); @@ -159,14 +160,14 @@ static Sequence *sequencer_prefetch_get_original_sequence(Sequence *seq, ListBas } /* for cache context swapping */ -Sequence *BKE_sequencer_prefetch_get_original_sequence(Sequence *seq, Scene *scene) +Sequence *seq_prefetch_get_original_sequence(Sequence *seq, Scene *scene) { Editing *ed = scene->ed; return sequencer_prefetch_get_original_sequence(seq, &ed->seqbase); } /* for cache context swapping */ -SeqRenderData *BKE_sequencer_prefetch_get_original_context(const SeqRenderData *context) +SeqRenderData *seq_prefetch_get_original_context(const SeqRenderData *context) { PrefetchJob *pfjob = seq_prefetch_job_get(context->scene); @@ -177,11 +178,11 @@ static bool seq_prefetch_is_cache_full(Scene *scene) { PrefetchJob *pfjob = seq_prefetch_job_get(scene); - if (!BKE_sequencer_cache_is_full(pfjob->scene)) { + if (!seq_cache_is_full()) { return false; } - return BKE_sequencer_cache_recycle_item(pfjob->scene) == false; + return seq_cache_recycle_item(pfjob->scene) == false; } static float seq_prefetch_cfra(PrefetchJob *pfjob) @@ -193,7 +194,7 @@ static AnimationEvalContext seq_prefetch_anim_eval_context(PrefetchJob *pfjob) return BKE_animsys_eval_context_construct(pfjob->depsgraph, seq_prefetch_cfra(pfjob)); } -void BKE_sequencer_prefetch_get_time_range(Scene *scene, int *start, int *end) +void seq_prefetch_get_time_range(Scene *scene, int *start, int *end) { PrefetchJob *pfjob = seq_prefetch_job_get(scene); @@ -256,18 +257,18 @@ static void seq_prefetch_update_area(PrefetchJob *pfjob) } } -void BKE_sequencer_prefetch_stop_all(void) +void SEQ_prefetch_stop_all(void) { /*TODO(Richard): Use wm_jobs for prefetch, or pass main. */ for (Scene *scene = G.main->scenes.first; scene; scene = scene->id.next) { - BKE_sequencer_prefetch_stop(scene); + SEQ_prefetch_stop(scene); } } /* Use also to update scene and context changes * This function should almost always be called by cache invalidation, not directly. */ -void BKE_sequencer_prefetch_stop(Scene *scene) +void SEQ_prefetch_stop(Scene *scene) { PrefetchJob *pfjob; pfjob = seq_prefetch_job_get(scene); @@ -338,14 +339,14 @@ static void seq_prefetch_resume(Scene *scene) } } -void BKE_sequencer_prefetch_free(Scene *scene) +void seq_prefetch_free(Scene *scene) { PrefetchJob *pfjob = seq_prefetch_job_get(scene); if (!pfjob) { return; } - BKE_sequencer_prefetch_stop(scene); + SEQ_prefetch_stop(scene); BLI_threadpool_remove(&pfjob->threads, pfjob); BLI_threadpool_end(&pfjob->threads); @@ -372,28 +373,28 @@ static bool seq_prefetch_do_skip_frame(Scene *scene) if (seq_arr[i]->type == SEQ_TYPE_SCENE && (seq_arr[i]->flag & SEQ_SCENE_STRIPS) == 0) { int cached_types = 0; - ibuf = BKE_sequencer_cache_get(ctx, seq_arr[i], cfra, SEQ_CACHE_STORE_FINAL_OUT, false); + ibuf = seq_cache_get(ctx, seq_arr[i], cfra, SEQ_CACHE_STORE_FINAL_OUT, false); if (ibuf != NULL) { cached_types |= SEQ_CACHE_STORE_FINAL_OUT; IMB_freeImBuf(ibuf); ibuf = NULL; } - ibuf = BKE_sequencer_cache_get(ctx, seq_arr[i], cfra, SEQ_CACHE_STORE_FINAL_OUT, false); + ibuf = seq_cache_get(ctx, seq_arr[i], cfra, SEQ_CACHE_STORE_FINAL_OUT, false); if (ibuf != NULL) { cached_types |= SEQ_CACHE_STORE_COMPOSITE; IMB_freeImBuf(ibuf); ibuf = NULL; } - ibuf = BKE_sequencer_cache_get(ctx, seq_arr[i], cfra, SEQ_CACHE_STORE_PREPROCESSED, false); + ibuf = seq_cache_get(ctx, seq_arr[i], cfra, SEQ_CACHE_STORE_PREPROCESSED, false); if (ibuf != NULL) { cached_types |= SEQ_CACHE_STORE_PREPROCESSED; IMB_freeImBuf(ibuf); ibuf = NULL; } - ibuf = BKE_sequencer_cache_get(ctx, seq_arr[i], cfra, SEQ_CACHE_STORE_RAW, false); + ibuf = seq_cache_get(ctx, seq_arr[i], cfra, SEQ_CACHE_STORE_RAW, false); if (ibuf != NULL) { cached_types |= SEQ_CACHE_STORE_RAW; IMB_freeImBuf(ibuf); @@ -463,8 +464,7 @@ static void *seq_prefetch_frames(void *job) } ImBuf *ibuf = SEQ_render_give_ibuf(&pfjob->context_cpy, seq_prefetch_cfra(pfjob), 0); - BKE_sequencer_cache_free_temp_cache( - pfjob->scene, pfjob->context.task_id, seq_prefetch_cfra(pfjob)); + seq_cache_free_temp_cache(pfjob->scene, pfjob->context.task_id, seq_prefetch_cfra(pfjob)); IMB_freeImBuf(ibuf); /* Suspend thread if there is nothing to be prefetched. */ @@ -484,15 +484,14 @@ static void *seq_prefetch_frames(void *job) pfjob->num_frames_prefetched++; } - BKE_sequencer_cache_free_temp_cache( - pfjob->scene, pfjob->context.task_id, seq_prefetch_cfra(pfjob)); + seq_cache_free_temp_cache(pfjob->scene, pfjob->context.task_id, seq_prefetch_cfra(pfjob)); pfjob->running = false; pfjob->scene_eval->ed->prefetch_job = NULL; return NULL; } -static PrefetchJob *seq_prefetch_start(const SeqRenderData *context, float cfra) +static PrefetchJob *seq_prefetch_start_ex(const SeqRenderData *context, float cfra) { PrefetchJob *pfjob = seq_prefetch_job_get(context->scene); @@ -529,7 +528,7 @@ static PrefetchJob *seq_prefetch_start(const SeqRenderData *context, float cfra) } /* Start or resume prefetching*/ -void BKE_sequencer_prefetch_start(const SeqRenderData *context, float timeline_frame, float cost) +void seq_prefetch_start(const SeqRenderData *context, float timeline_frame) { Scene *scene = context->scene; Editing *ed = scene->ed; @@ -538,27 +537,26 @@ void BKE_sequencer_prefetch_start(const SeqRenderData *context, float timeline_f if (!context->is_prefetch_render && !context->is_proxy_render) { bool playing = seq_prefetch_is_playing(context->bmain); bool scrubbing = seq_prefetch_is_scrubbing(context->bmain); - bool running = BKE_sequencer_prefetch_job_is_running(scene); + bool running = seq_prefetch_job_is_running(scene); seq_prefetch_resume(scene); /* conditions to start: - * prefetch enabled, prefetch not running, not scrubbing, - * not playing and rendering-expensive footage, cache storage enabled, has strips to render, - * not rendering, not doing modal transform - important, see D7820. + * prefetch enabled, prefetch not running, not scrubbing, not playing, + * cache storage enabled, has strips to render, not rendering, not doing modal transform - + * important, see D7820. */ - if ((ed->cache_flag & SEQ_CACHE_PREFETCH_ENABLE) && !running && !scrubbing && - !(playing && cost > 0.9) && ed->cache_flag & SEQ_CACHE_ALL_TYPES && has_strips && - !G.is_rendering && !G.moving) { + if ((ed->cache_flag & SEQ_CACHE_PREFETCH_ENABLE) && !running && !scrubbing && !playing && + ed->cache_flag & SEQ_CACHE_ALL_TYPES && has_strips && !G.is_rendering && !G.moving) { - seq_prefetch_start(context, timeline_frame); + seq_prefetch_start_ex(context, timeline_frame); } } } -bool BKE_sequencer_prefetch_need_redraw(Main *bmain, Scene *scene) +bool SEQ_prefetch_need_redraw(Main *bmain, Scene *scene) { bool playing = seq_prefetch_is_playing(bmain); bool scrubbing = seq_prefetch_is_scrubbing(bmain); - bool running = BKE_sequencer_prefetch_job_is_running(scene); + bool running = seq_prefetch_job_is_running(scene); bool suspended = seq_prefetch_job_is_waiting(scene); /* force redraw, when prefetching and using cache view. */ diff --git a/source/blender/sequencer/intern/prefetch.h b/source/blender/sequencer/intern/prefetch.h index aa47a9dbcfc..8cfc6bf90bd 100644 --- a/source/blender/sequencer/intern/prefetch.h +++ b/source/blender/sequencer/intern/prefetch.h @@ -27,26 +27,20 @@ extern "C" { #endif -struct ImBuf; -struct Main; struct Scene; -struct Sequence; struct SeqRenderData; +struct Sequence; #ifdef __cplusplus } #endif -void BKE_sequencer_prefetch_start(const struct SeqRenderData *context, - float timeline_frame, - float cost); -void BKE_sequencer_prefetch_free(struct Scene *scene); -bool BKE_sequencer_prefetch_job_is_running(struct Scene *scene); -void BKE_sequencer_prefetch_get_time_range(struct Scene *scene, int *start, int *end); -struct SeqRenderData *BKE_sequencer_prefetch_get_original_context( - const struct SeqRenderData *context); -struct Sequence *BKE_sequencer_prefetch_get_original_sequence(struct Sequence *seq, - struct Scene *scene); +void seq_prefetch_start(const struct SeqRenderData *context, float timeline_frame); +void seq_prefetch_free(struct Scene *scene); +bool seq_prefetch_job_is_running(struct Scene *scene); +void seq_prefetch_get_time_range(struct Scene *scene, int *start, int *end); +struct SeqRenderData *seq_prefetch_get_original_context(const struct SeqRenderData *context); +struct Sequence *seq_prefetch_get_original_sequence(struct Sequence *seq, struct Scene *scene); #ifdef __cplusplus } diff --git a/source/blender/sequencer/intern/proxy.c b/source/blender/sequencer/intern/proxy.c index ff65216d987..22d8daba696 100644 --- a/source/blender/sequencer/intern/proxy.c +++ b/source/blender/sequencer/intern/proxy.c @@ -54,6 +54,8 @@ #include "IMB_imbuf_types.h" #include "IMB_metadata.h" +#include "SEQ_proxy.h" +#include "SEQ_render.h" #include "SEQ_sequencer.h" #include "multiview.h" @@ -422,7 +424,7 @@ bool SEQ_proxy_rebuild_context(Main *bmain, context = MEM_callocN(sizeof(SeqIndexBuildContext), "seq proxy rebuild context"); - nseq = BKE_sequence_dupli_recursive(scene, scene, NULL, seq, 0); + nseq = SEQ_sequence_dupli_recursive(scene, scene, NULL, seq, 0); context->tc_flags = nseq->strip->proxy->build_tc_flags; context->size_flags = nseq->strip->proxy->build_size_flags; diff --git a/source/blender/sequencer/intern/proxy.h b/source/blender/sequencer/intern/proxy.h index a362a318a5a..a65fdcd42fe 100644 --- a/source/blender/sequencer/intern/proxy.h +++ b/source/blender/sequencer/intern/proxy.h @@ -27,10 +27,10 @@ extern "C" { #endif -struct anim; struct ImBuf; struct SeqRenderData; struct Sequence; +struct anim; #define PROXY_MAXFILE (2 * FILE_MAXDIR + FILE_MAXFILE) struct ImBuf *seq_proxy_fetch(const struct SeqRenderData *context, diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c index 008ea1cd3a0..8d6a61f3c5d 100644 --- a/source/blender/sequencer/intern/render.c +++ b/source/blender/sequencer/intern/render.c @@ -64,7 +64,12 @@ #include "RE_engine.h" #include "RE_pipeline.h" +#include "SEQ_effects.h" +#include "SEQ_modifier.h" +#include "SEQ_proxy.h" +#include "SEQ_render.h" #include "SEQ_sequencer.h" +#include "SEQ_utils.h" #include "effects.h" #include "image_cache.h" @@ -337,16 +342,17 @@ static int evaluate_seq_frame_gen(Sequence **seq_arr, return totseq; } -int SEQ_render_evaluate_frame(Scene *scene, int timeline_frame) +/** + * Count number of strips in timeline at timeline_frame + * + * \param seqbase: ListBase in which strips are located + * \param timeline_frame: frame on timeline from where gaps are searched for + * \return number of strips + */ +int SEQ_render_evaluate_frame(ListBase *seqbase, int timeline_frame) { - Editing *ed = BKE_sequencer_editing_get(scene, false); Sequence *seq_arr[MAXSEQ + 1]; - - if (ed == NULL) { - return 0; - } - - return evaluate_seq_frame_gen(seq_arr, ed->seqbasep, timeline_frame, 0); + return evaluate_seq_frame_gen(seq_arr, seqbase, timeline_frame, 0); } static bool video_seq_is_rendered(Sequence *seq) @@ -397,24 +403,6 @@ int seq_get_shown_sequences(ListBase *seqbasep, return cnt; } -/* Estimate time spent by the program rendering the strip */ -static clock_t seq_estimate_render_cost_begin(void) -{ - return clock(); -} - -static float seq_estimate_render_cost_end(Scene *scene, clock_t begin) -{ - clock_t end = clock(); - float time_spent = (float)(end - begin); - float time_max = (1.0f / scene->r.frs_sec) * CLOCKS_PER_SEC; - - if (time_max != 0) { - return time_spent / time_max; - } - - return 1; -} /** \} */ /* -------------------------------------------------------------------- */ @@ -460,9 +448,9 @@ static bool sequencer_use_crop(const Sequence *seq) return false; } -static bool BKE_sequencer_input_have_to_preprocess(const SeqRenderData *context, - Sequence *seq, - float UNUSED(timeline_frame)) +static bool seq_input_have_to_preprocess(const SeqRenderData *context, + Sequence *seq, + float UNUSED(timeline_frame)) { float mul; @@ -527,7 +515,6 @@ static void sequencer_image_transform_init(void *handle_v, handle->ibuf_source = init_data->ibuf_source; handle->ibuf_out = init_data->ibuf_out; handle->transform = init_data->transform; - handle->scale_to_fit = init_data->scale_to_fit; handle->image_scale_factor = init_data->image_scale_factor; handle->for_render = init_data->for_render; @@ -539,8 +526,8 @@ static void *sequencer_image_transform_do_thread(void *data_v) { const ImageTransformThreadData *data = (ImageTransformThreadData *)data_v; const StripTransform *transform = data->transform; - const float scale_x = transform->scale_x * data->scale_to_fit; - const float scale_y = transform->scale_y * data->scale_to_fit; + const float scale_x = transform->scale_x * data->image_scale_factor; + const float scale_y = transform->scale_y * data->image_scale_factor; const float scale_to_fit_offs_x = (data->ibuf_out->x - data->ibuf_source->x) / 2; const float scale_to_fit_offs_y = (data->ibuf_out->y - data->ibuf_source->y) / 2; const float translate_x = transform->xofs * data->image_scale_factor + scale_to_fit_offs_x; @@ -625,10 +612,6 @@ static ImBuf *input_preprocess(const SeqRenderData *context, IMB_filtery(preprocessed_ibuf); } - /* Calculate scale factor, so image fits in preview area with original aspect ratio. */ - const float scale_to_fit_factor = MIN2((float)context->rectx / (float)ibuf->x, - (float)context->recty / (float)ibuf->y); - /* Get scale factor if preview resolution doesn't match project resolution. */ float preview_scale_factor; if (context->preview_render_size == SEQ_RENDER_SIZE_SCENE) { @@ -647,10 +630,10 @@ static ImBuf *input_preprocess(const SeqRenderData *context, const int height = ibuf->y; const StripCrop *c = seq->strip->crop; - const int left = c->left / scale_to_fit_factor * preview_scale_factor; - const int right = c->right / scale_to_fit_factor * preview_scale_factor; - const int top = c->top / scale_to_fit_factor * preview_scale_factor; - const int bottom = c->bottom / scale_to_fit_factor * preview_scale_factor; + const int left = c->left; + const int right = c->right; + const int top = c->top; + const int bottom = c->bottom; const float col[4] = {0.0f, 0.0f, 0.0f, 0.0f}; /* Left. */ @@ -672,7 +655,6 @@ static ImBuf *input_preprocess(const SeqRenderData *context, init_data.ibuf_source = ibuf; init_data.ibuf_out = preprocessed_ibuf; init_data.transform = seq->strip->transform; - init_data.scale_to_fit = scale_to_fit_factor; init_data.image_scale_factor = preview_scale_factor; init_data.for_render = context->for_render; IMB_processor_apply_threaded(context->recty, @@ -722,8 +704,7 @@ static ImBuf *input_preprocess(const SeqRenderData *context, } if (seq->modifiers.first) { - ImBuf *ibuf_new = BKE_sequence_modifier_apply_stack( - context, seq, preprocessed_ibuf, timeline_frame); + ImBuf *ibuf_new = SEQ_modifier_apply_stack(context, seq, preprocessed_ibuf, timeline_frame); if (ibuf_new != preprocessed_ibuf) { IMB_metadata_copy(ibuf_new, preprocessed_ibuf); @@ -739,7 +720,6 @@ static ImBuf *seq_render_preprocess_ibuf(const SeqRenderData *context, Sequence *seq, ImBuf *ibuf, float timeline_frame, - clock_t begin, bool use_preprocess, const bool is_proxy_image) { @@ -749,22 +729,15 @@ static ImBuf *seq_render_preprocess_ibuf(const SeqRenderData *context, } if (use_preprocess) { - float cost = seq_estimate_render_cost_end(context->scene, begin); - /* Proxies are not stored in cache. */ if (!is_proxy_image) { - BKE_sequencer_cache_put( - context, seq, timeline_frame, SEQ_CACHE_STORE_RAW, ibuf, cost, false); + seq_cache_put(context, seq, timeline_frame, SEQ_CACHE_STORE_RAW, ibuf, false); } - /* Reset timer so we can get partial render time. */ - begin = seq_estimate_render_cost_begin(); ibuf = input_preprocess(context, seq, timeline_frame, ibuf); } - float cost = seq_estimate_render_cost_end(context->scene, begin); - BKE_sequencer_cache_put( - context, seq, timeline_frame, SEQ_CACHE_STORE_PREPROCESSED, ibuf, cost, false); + seq_cache_put(context, seq, timeline_frame, SEQ_CACHE_STORE_PREPROCESSED, ibuf, false); return ibuf; } @@ -873,7 +846,7 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context, float fac, facf; int early_out; int i; - struct SeqEffectHandle sh = BKE_sequence_get_effect(seq); + struct SeqEffectHandle sh = SEQ_effect_handle_get(seq); FCurve *fcu = NULL; ImBuf *ibuf[3]; Sequence *input[3]; @@ -915,8 +888,7 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context, for (i = 0; i < 3; i++) { /* Speed effect requires time remapping of `timeline_frame` for input(s). */ if (input[0] && seq->type == SEQ_TYPE_SPEED) { - float target_frame = BKE_sequencer_speed_effect_target_frame_get( - context, seq, timeline_frame, i); + float target_frame = seq_speed_effect_target_frame_get(context, seq, timeline_frame, i); ibuf[i] = seq_render_strip(context, state, input[0], target_frame); } else { /* Other effects. */ @@ -926,7 +898,7 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context, } } - if (ibuf[0] && (ibuf[1] || BKE_sequence_effect_get_num_inputs(seq->type) == 1)) { + if (ibuf[0] && (ibuf[1] || SEQ_effect_get_num_inputs(seq->type) == 1)) { if (sh.multithreaded) { out = seq_render_effect_execute_threaded( &sh, context, seq, timeline_frame, fac, facf, ibuf[0], ibuf[1], ibuf[2]); @@ -1077,7 +1049,7 @@ static ImBuf *seq_render_image_strip(const SeqRenderData *context, if (view_id != context->view_id) { ibufs_arr[view_id] = seq_render_preprocess_ibuf( - &localcontext, seq, ibufs_arr[view_id], timeline_frame, clock(), true, false); + &localcontext, seq, ibufs_arr[view_id], timeline_frame, true, false); } } @@ -1227,7 +1199,7 @@ static ImBuf *seq_render_movie_strip(const SeqRenderData *context, if (view_id != context->view_id) { ibuf_arr[view_id] = seq_render_preprocess_ibuf( - &localcontext, seq, ibuf_arr[view_id], timeline_frame, clock(), true, false); + &localcontext, seq, ibuf_arr[view_id], timeline_frame, true, false); } } @@ -1633,8 +1605,8 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, } if (view_id != context->view_id) { - BKE_sequencer_cache_put( - &localcontext, seq, timeline_frame, SEQ_CACHE_STORE_RAW, ibufs_arr[view_id], 0, false); + seq_cache_put( + &localcontext, seq, timeline_frame, SEQ_CACHE_STORE_RAW, ibufs_arr[view_id], false); } RE_ReleaseResultImage(re); @@ -1682,7 +1654,7 @@ static ImBuf *do_render_strip_seqbase(const SeqRenderData *context, ListBase *seqbase = NULL; int offset; - seqbase = BKE_sequence_seqbase_get(seq, &offset); + seqbase = SEQ_get_seqbase_from_sequence(seq, &offset); if (seqbase && !BLI_listbase_is_empty(seqbase)) { @@ -1809,17 +1781,14 @@ ImBuf *seq_render_strip(const SeqRenderData *context, bool use_preprocess = false; bool is_proxy_image = false; - clock_t begin = seq_estimate_render_cost_begin(); - - ibuf = BKE_sequencer_cache_get( - context, seq, timeline_frame, SEQ_CACHE_STORE_PREPROCESSED, false); + ibuf = seq_cache_get(context, seq, timeline_frame, SEQ_CACHE_STORE_PREPROCESSED, false); if (ibuf != NULL) { return ibuf; } /* Proxies are not stored in cache. */ if (!SEQ_can_use_proxy(seq, SEQ_rendersize_to_proxysize(context->preview_render_size))) { - ibuf = BKE_sequencer_cache_get(context, seq, timeline_frame, SEQ_CACHE_STORE_RAW, false); + ibuf = seq_cache_get(context, seq, timeline_frame, SEQ_CACHE_STORE_RAW, false); } if (ibuf == NULL) { @@ -1827,9 +1796,9 @@ ImBuf *seq_render_strip(const SeqRenderData *context, } if (ibuf) { - use_preprocess = BKE_sequencer_input_have_to_preprocess(context, seq, timeline_frame); + use_preprocess = seq_input_have_to_preprocess(context, seq, timeline_frame); ibuf = seq_render_preprocess_ibuf( - context, seq, ibuf, timeline_frame, begin, use_preprocess, is_proxy_image); + context, seq, ibuf, timeline_frame, use_preprocess, is_proxy_image); } if (ibuf == NULL) { @@ -1856,7 +1825,7 @@ static bool seq_must_swap_input_in_blend_mode(Sequence *seq) static int seq_get_early_out_for_blend_mode(Sequence *seq) { - struct SeqEffectHandle sh = BKE_sequence_get_blend(seq); + struct SeqEffectHandle sh = seq_effect_get_sequence_blend(seq); float facf = seq->blend_opacity / 100.0f; int early_out = sh.early_out(seq, facf, facf); @@ -1879,7 +1848,7 @@ static ImBuf *seq_render_strip_stack_apply_effect( const SeqRenderData *context, Sequence *seq, float timeline_frame, ImBuf *ibuf1, ImBuf *ibuf2) { ImBuf *out; - struct SeqEffectHandle sh = BKE_sequence_get_blend(seq); + struct SeqEffectHandle sh = seq_effect_get_sequence_blend(seq); float facf = seq->blend_opacity / 100.0f; int swap_input = seq_must_swap_input_in_blend_mode(seq); @@ -1915,7 +1884,6 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, int count; int i; ImBuf *out = NULL; - clock_t begin; count = seq_get_shown_sequences(seqbasep, timeline_frame, chanshown, (Sequence **)&seq_arr); @@ -1927,7 +1895,7 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, int early_out; Sequence *seq = seq_arr[i]; - out = BKE_sequencer_cache_get(context, seq, timeline_frame, SEQ_CACHE_STORE_COMPOSITE, false); + out = seq_cache_get(context, seq, timeline_frame, SEQ_CACHE_STORE_COMPOSITE, false); if (out) { break; @@ -1951,16 +1919,13 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, break; case EARLY_DO_EFFECT: if (i == 0) { - begin = seq_estimate_render_cost_begin(); - ImBuf *ibuf1 = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect); ImBuf *ibuf2 = seq_render_strip(context, state, seq, timeline_frame); out = seq_render_strip_stack_apply_effect(context, seq, timeline_frame, ibuf1, ibuf2); - float cost = seq_estimate_render_cost_end(context->scene, begin); - BKE_sequencer_cache_put( - context, seq_arr[i], timeline_frame, SEQ_CACHE_STORE_COMPOSITE, out, cost, false); + seq_cache_put( + context, seq_arr[i], timeline_frame, SEQ_CACHE_STORE_COMPOSITE, out, false); IMB_freeImBuf(ibuf1); IMB_freeImBuf(ibuf2); @@ -1974,7 +1939,6 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, i++; for (; i < count; i++) { - begin = seq_estimate_render_cost_begin(); Sequence *seq = seq_arr[i]; if (seq_get_early_out_for_blend_mode(seq) == EARLY_DO_EFFECT) { @@ -1987,9 +1951,7 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, IMB_freeImBuf(ibuf2); } - float cost = seq_estimate_render_cost_end(context->scene, begin); - BKE_sequencer_cache_put( - context, seq_arr[i], timeline_frame, SEQ_CACHE_STORE_COMPOSITE, out, cost, false); + seq_cache_put(context, seq_arr[i], timeline_frame, SEQ_CACHE_STORE_COMPOSITE, out, false); } return out; @@ -2003,7 +1965,7 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, ImBuf *SEQ_render_give_ibuf(const SeqRenderData *context, float timeline_frame, int chanshown) { Scene *scene = context->scene; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); ListBase *seqbasep; if (ed == NULL) { @@ -2028,42 +1990,28 @@ ImBuf *SEQ_render_give_ibuf(const SeqRenderData *context, float timeline_frame, count = seq_get_shown_sequences(seqbasep, timeline_frame, chanshown, seq_arr); if (count) { - out = BKE_sequencer_cache_get( + out = seq_cache_get( context, seq_arr[count - 1], timeline_frame, SEQ_CACHE_STORE_FINAL_OUT, false); } - BKE_sequencer_cache_free_temp_cache(context->scene, context->task_id, timeline_frame); - - clock_t begin = seq_estimate_render_cost_begin(); - float cost = 0; + seq_cache_free_temp_cache(context->scene, context->task_id, timeline_frame); if (count && !out) { BLI_mutex_lock(&seq_render_mutex); out = seq_render_strip_stack(context, &state, seqbasep, timeline_frame, chanshown); - cost = seq_estimate_render_cost_end(context->scene, begin); if (context->is_prefetch_render) { - BKE_sequencer_cache_put(context, - seq_arr[count - 1], - timeline_frame, - SEQ_CACHE_STORE_FINAL_OUT, - out, - cost, - false); + seq_cache_put( + context, seq_arr[count - 1], timeline_frame, SEQ_CACHE_STORE_FINAL_OUT, out, false); } else { - BKE_sequencer_cache_put_if_possible(context, - seq_arr[count - 1], - timeline_frame, - SEQ_CACHE_STORE_FINAL_OUT, - out, - cost, - false); + seq_cache_put_if_possible( + context, seq_arr[count - 1], timeline_frame, SEQ_CACHE_STORE_FINAL_OUT, out, false); } BLI_mutex_unlock(&seq_render_mutex); } - BKE_sequencer_prefetch_start(context, timeline_frame, cost); + seq_prefetch_start(context, timeline_frame); return out; } diff --git a/source/blender/sequencer/intern/render.h b/source/blender/sequencer/intern/render.h index d5affeb547b..6875087df82 100644 --- a/source/blender/sequencer/intern/render.h +++ b/source/blender/sequencer/intern/render.h @@ -27,12 +27,12 @@ extern "C" { #endif -struct Editing; struct ImBuf; struct ListBase; struct Scene; struct SeqRenderData; struct Sequence; +struct SeqEffectHandle; #define EARLY_NO_INPUT -1 #define EARLY_DO_EFFECT 0 @@ -51,7 +51,7 @@ struct ImBuf *seq_render_give_ibuf_seqbase(const struct SeqRenderData *context, int chan_shown, struct ListBase *seqbasep); struct ImBuf *seq_render_effect_execute_threaded(struct SeqEffectHandle *sh, - const SeqRenderData *context, + const struct SeqRenderData *context, struct Sequence *seq, float timeline_frame, float facf0, diff --git a/source/blender/sequencer/intern/sequencer.c b/source/blender/sequencer/intern/sequencer.c index 0ebf8f3c8e7..b589a75fa42 100644 --- a/source/blender/sequencer/intern/sequencer.c +++ b/source/blender/sequencer/intern/sequencer.c @@ -44,7 +44,13 @@ #include "IMB_colormanagement.h" #include "IMB_imbuf.h" +#include "SEQ_effects.h" +#include "SEQ_iterator.h" +#include "SEQ_modifier.h" +#include "SEQ_relations.h" +#include "SEQ_select.h" #include "SEQ_sequencer.h" +#include "SEQ_utils.h" #include "image_cache.h" #include "prefetch.h" @@ -104,7 +110,7 @@ static void seq_free_strip(Strip *strip) MEM_freeN(strip); } -Sequence *BKE_sequence_alloc(ListBase *lb, int timeline_frame, int machine, int type) +Sequence *SEQ_sequence_alloc(ListBase *lb, int timeline_frame, int machine, int type) { Sequence *seq; @@ -129,13 +135,13 @@ Sequence *BKE_sequence_alloc(ListBase *lb, int timeline_frame, int machine, int seq->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Sequence Stereo Format"); seq->cache_flag = SEQ_CACHE_STORE_RAW | SEQ_CACHE_STORE_PREPROCESSED | SEQ_CACHE_STORE_COMPOSITE; - BKE_sequence_session_uuid_generate(seq); + SEQ_relations_session_uuid_generate(seq); return seq; } /* only give option to skip cache locally (static func) */ -static void BKE_sequence_free_ex(Scene *scene, +static void seq_sequence_free_ex(Scene *scene, Sequence *seq, const bool do_cache, const bool do_id_user, @@ -145,10 +151,10 @@ static void BKE_sequence_free_ex(Scene *scene, seq_free_strip(seq->strip); } - BKE_sequence_free_anim(seq); + SEQ_relations_sequence_free_anim(seq); if (seq->type & SEQ_TYPE_EFFECT) { - struct SeqEffectHandle sh = BKE_sequence_get_effect(seq); + struct SeqEffectHandle sh = SEQ_effect_handle_get(seq); sh.free(seq, do_id_user); } @@ -186,7 +192,7 @@ static void BKE_sequence_free_ex(Scene *scene, } /* free modifiers */ - BKE_sequence_modifier_clear(seq); + SEQ_modifier_clear(seq); /* free cached data used by this strip, * also invalidate cache for all dependent sequences @@ -194,20 +200,20 @@ static void BKE_sequence_free_ex(Scene *scene, * be _very_ careful here, invalidating cache loops over the scene sequences and * assumes the listbase is valid for all strips, * this may not be the case if lists are being freed. - * this is optional BKE_sequence_invalidate_cache + * this is optional SEQ_relations_invalidate_cache */ if (do_cache) { if (scene) { - BKE_sequence_invalidate_cache_raw(scene, seq); + SEQ_relations_invalidate_cache_raw(scene, seq); } } MEM_freeN(seq); } -void BKE_sequence_free(Scene *scene, Sequence *seq, const bool do_clean_animdata) +void SEQ_sequence_free(Scene *scene, Sequence *seq, const bool do_clean_animdata) { - BKE_sequence_free_ex(scene, seq, true, true, do_clean_animdata); + seq_sequence_free_ex(scene, seq, true, true, do_clean_animdata); } /* cache must be freed before calling this function @@ -221,18 +227,18 @@ void seq_free_sequence_recurse(Scene *scene, Sequence *seq, const bool do_id_use seq_free_sequence_recurse(scene, iseq, do_id_user); } - BKE_sequence_free_ex(scene, seq, false, do_id_user, true); + seq_sequence_free_ex(scene, seq, false, do_id_user, true); } -Editing *BKE_sequencer_editing_get(Scene *scene, bool alloc) +Editing *SEQ_editing_get(Scene *scene, bool alloc) { if (alloc) { - BKE_sequencer_editing_ensure(scene); + SEQ_editing_ensure(scene); } return scene->ed; } -Editing *BKE_sequencer_editing_ensure(Scene *scene) +Editing *SEQ_editing_ensure(Scene *scene) { if (scene->ed == NULL) { Editing *ed; @@ -243,13 +249,12 @@ Editing *BKE_sequencer_editing_ensure(Scene *scene) ed->cache_flag = SEQ_CACHE_STORE_FINAL_OUT; ed->cache_flag |= SEQ_CACHE_VIEW_FINAL_OUT; ed->cache_flag |= SEQ_CACHE_VIEW_ENABLE; - ed->recycle_max_cost = 10.0f; } return scene->ed; } -void BKE_sequencer_editing_free(Scene *scene, const bool do_id_user) +void SEQ_editing_free(Scene *scene, const bool do_id_user) { Editing *ed = scene->ed; Sequence *seq; @@ -258,12 +263,12 @@ void BKE_sequencer_editing_free(Scene *scene, const bool do_id_user) return; } - BKE_sequencer_prefetch_free(scene); - BKE_sequencer_cache_destruct(scene); + seq_prefetch_free(scene); + seq_cache_destruct(scene); SEQ_ALL_BEGIN (ed, seq) { /* handle cache freeing above */ - BKE_sequence_free_ex(scene, seq, false, do_id_user, false); + seq_sequence_free_ex(scene, seq, false, do_id_user, false); } SEQ_ALL_END; @@ -301,6 +306,46 @@ static void seq_new_fix_links_recursive(Sequence *seq) } } } + +SequencerToolSettings *SEQ_tool_settings_init(void) +{ + SequencerToolSettings *tool_settings = MEM_callocN(sizeof(SequencerToolSettings), + "Sequencer tool settings"); + tool_settings->fit_method = SEQ_SCALE_TO_FIT; + return tool_settings; +} + +void SEQ_tool_settings_free(SequencerToolSettings *tool_settings) +{ + MEM_freeN(tool_settings); +} + +eSeqImageFitMethod SEQ_tool_settings_fit_method_get(Scene *scene) +{ + const SequencerToolSettings *tool_settings = scene->toolsettings->sequencer_tool_settings; + return tool_settings->fit_method; +} + +void SEQ_tool_settings_fit_method_set(Scene *scene, eSeqImageFitMethod fit_method) +{ + SequencerToolSettings *tool_settings = scene->toolsettings->sequencer_tool_settings; + tool_settings->fit_method = fit_method; +} + +/** + * Get seqbase that is being viewed currently. This can be main seqbase or meta strip seqbase + * + * \param ed: sequence editor data + * \return pointer to active seqbase. returns NULL if ed is NULL + */ +ListBase *SEQ_active_seqbase_get(const Editing *ed) +{ + if (ed == NULL) { + return NULL; + } + + return ed->seqbasep; +} /** \} */ /* -------------------------------------------------------------------- */ @@ -316,7 +361,7 @@ static Sequence *seq_dupli(const Scene *scene_src, Sequence *seqn = MEM_dupallocN(seq); if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) { - BKE_sequence_session_uuid_generate(seq); + SEQ_relations_session_uuid_generate(seq); } seq->tmp = seqn; @@ -346,7 +391,7 @@ static Sequence *seq_dupli(const Scene *scene_src, if (seqn->modifiers.first) { BLI_listbase_clear(&seqn->modifiers); - BKE_sequence_modifier_list_copy(seqn, seq); + SEQ_modifier_list_copy(seqn, seq); } if (seq->type == SEQ_TYPE_META) { @@ -384,7 +429,7 @@ static Sequence *seq_dupli(const Scene *scene_src, } else if (seq->type & SEQ_TYPE_EFFECT) { struct SeqEffectHandle sh; - sh = BKE_sequence_get_effect(seq); + sh = SEQ_effect_handle_get(seq); if (sh.copy) { sh.copy(seqn, seq, flag); } @@ -408,11 +453,11 @@ static Sequence *seq_dupli(const Scene *scene_src, if (scene_src == scene_dst) { if (dupe_flag & SEQ_DUPE_UNIQUE_NAME) { - BKE_sequence_base_unique_name_recursive(&scene_dst->ed->seqbase, seqn); + SEQ_sequence_base_unique_name_recursive(&scene_dst->ed->seqbase, seqn); } if (dupe_flag & SEQ_DUPE_ANIM) { - BKE_sequencer_dupe_animdata(scene_dst, seq->name + 2, seqn->name + 2); + SEQ_dupe_animdata(scene_dst, seq->name + 2, seqn->name + 2); } } @@ -439,7 +484,7 @@ static Sequence *sequence_dupli_recursive_do(const Scene *scene_src, return seqn; } -Sequence *BKE_sequence_dupli_recursive( +Sequence *SEQ_sequence_dupli_recursive( const Scene *scene_src, Scene *scene_dst, ListBase *new_seq_list, Sequence *seq, int dupe_flag) { Sequence *seqn = sequence_dupli_recursive_do(scene_src, scene_dst, new_seq_list, seq, dupe_flag); @@ -450,7 +495,7 @@ Sequence *BKE_sequence_dupli_recursive( return seqn; } -void BKE_sequence_base_dupli_recursive(const Scene *scene_src, +void SEQ_sequence_base_dupli_recursive(const Scene *scene_src, Scene *scene_dst, ListBase *nseqbase, const ListBase *seqbase, @@ -459,7 +504,7 @@ void BKE_sequence_base_dupli_recursive(const Scene *scene_src, { Sequence *seq; Sequence *seqn = NULL; - Sequence *last_seq = BKE_sequencer_active_get((Scene *)scene_src); + Sequence *last_seq = SEQ_select_active_get((Scene *)scene_src); /* always include meta's strips */ int dupe_flag_recursive = dupe_flag | SEQ_DUPE_ALL | SEQ_DUPE_IS_RECURSIVE_CALL; @@ -474,13 +519,13 @@ void BKE_sequence_base_dupli_recursive(const Scene *scene_src, } if (seq->type == SEQ_TYPE_META) { - BKE_sequence_base_dupli_recursive( + SEQ_sequence_base_dupli_recursive( scene_src, scene_dst, &seqn->seqbase, &seq->seqbase, dupe_flag_recursive, flag); } if (dupe_flag & SEQ_DUPE_CONTEXT) { if (seq == last_seq) { - BKE_sequencer_active_set(scene_dst, seqn); + SEQ_select_active_set(scene_dst, seqn); } } } @@ -505,13 +550,13 @@ static size_t sequencer_rna_path_prefix(char str[SEQ_RNAPATH_MAXSTR], const char { char name_esc[SEQ_NAME_MAXSTR * 2]; - BLI_strescape(name_esc, name, sizeof(name_esc)); + BLI_str_escape(name_esc, name, sizeof(name_esc)); return BLI_snprintf_rlen( str, SEQ_RNAPATH_MAXSTR, "sequence_editor.sequences_all[\"%s\"]", name_esc); } /* XXX - hackish function needed for transforming strips! TODO - have some better solution */ -void BKE_sequencer_offset_animdata(Scene *scene, Sequence *seq, int ofs) +void SEQ_offset_animdata(Scene *scene, Sequence *seq, int ofs) { char str[SEQ_RNAPATH_MAXSTR]; size_t str_len; @@ -546,7 +591,7 @@ void BKE_sequencer_offset_animdata(Scene *scene, Sequence *seq, int ofs) DEG_id_tag_update(&scene->adt->action->id, ID_RECALC_ANIMATION); } -void BKE_sequencer_dupe_animdata(Scene *scene, const char *name_src, const char *name_dst) +void SEQ_dupe_animdata(Scene *scene, const char *name_src, const char *name_dst) { char str_from[SEQ_RNAPATH_MAXSTR]; size_t str_from_len; @@ -609,4 +654,11 @@ static void seq_free_animdata(Scene *scene, Sequence *seq) } #undef SEQ_RNAPATH_MAXSTR + +SequencerToolSettings *SEQ_tool_settings_copy(SequencerToolSettings *tool_settings) +{ + SequencerToolSettings *tool_settings_copy = MEM_dupallocN(tool_settings); + return tool_settings_copy; +} + /** \} */ diff --git a/source/blender/sequencer/intern/sound.c b/source/blender/sequencer/intern/sound.c index 9549938abee..1054dbeeba6 100644 --- a/source/blender/sequencer/intern/sound.c +++ b/source/blender/sequencer/intern/sound.c @@ -36,30 +36,11 @@ #include "BKE_scene.h" #include "BKE_sound.h" -#include "SEQ_sequencer.h" +#include "SEQ_sound.h" +#include "SEQ_time.h" #include "strip_time.h" -void BKE_sequence_sound_init(Scene *scene, Sequence *seq); - -void BKE_sequence_sound_init(Scene *scene, Sequence *seq) -{ - if (seq->type == SEQ_TYPE_META) { - Sequence *seq_child; - for (seq_child = seq->seqbase.first; seq_child; seq_child = seq_child->next) { - BKE_sequence_sound_init(scene, seq_child); - } - } - else { - if (seq->sound) { - seq->scene_sound = BKE_sound_add_scene_sound_defaults(scene, seq); - } - if (seq->scene) { - seq->scene_sound = BKE_sound_scene_add_scene_sound_defaults(scene, seq); - } - } -} - /* Unlike _update_sound_ funcs, these ones take info from audaspace to update sequence length! */ #ifdef WITH_AUDASPACE static bool sequencer_refresh_sound_length_recursive(Main *bmain, Scene *scene, ListBase *seqbase) @@ -70,7 +51,7 @@ static bool sequencer_refresh_sound_length_recursive(Main *bmain, Scene *scene, for (seq = seqbase->first; seq; seq = seq->next) { if (seq->type == SEQ_TYPE_META) { if (sequencer_refresh_sound_length_recursive(bmain, scene, &seq->seqbase)) { - BKE_sequence_calc(scene, seq); + SEQ_time_update_sequence(scene, seq); changed = true; } } @@ -86,7 +67,7 @@ static bool sequencer_refresh_sound_length_recursive(Main *bmain, Scene *scene, seq->endofs *= fac; seq->start += (old - seq->startofs); /* So that visual/"real" start frame does not change! */ - BKE_sequence_calc(scene, seq); + SEQ_time_update_sequence(scene, seq); changed = true; } } @@ -94,7 +75,7 @@ static bool sequencer_refresh_sound_length_recursive(Main *bmain, Scene *scene, } #endif -void BKE_sequencer_refresh_sound_length(Main *bmain, Scene *scene) +void SEQ_sound_update_length(Main *bmain, Scene *scene) { #ifdef WITH_AUDASPACE if (scene->ed) { @@ -105,7 +86,7 @@ void BKE_sequencer_refresh_sound_length(Main *bmain, Scene *scene) #endif } -void BKE_sequencer_update_sound_bounds_all(Scene *scene) +void SEQ_sound_update_bounds_all(Scene *scene) { Editing *ed = scene->ed; @@ -117,13 +98,13 @@ void BKE_sequencer_update_sound_bounds_all(Scene *scene) seq_update_sound_bounds_recursive(scene, seq); } else if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) { - BKE_sequencer_update_sound_bounds(scene, seq); + SEQ_sound_update_bounds(scene, seq); } } } } -void BKE_sequencer_update_sound_bounds(Scene *scene, Sequence *seq) +void SEQ_sound_update_bounds(Scene *scene, Sequence *seq) { if (seq->type == SEQ_TYPE_SCENE) { if (seq->scene && seq->scene_sound) { @@ -155,7 +136,7 @@ static void seq_update_sound_recursive(Scene *scene, ListBase *seqbasep, bSound } } -void BKE_sequencer_update_sound(Scene *scene, bSound *sound) +void SEQ_sound_update(Scene *scene, bSound *sound) { if (scene->ed) { seq_update_sound_recursive(scene, &scene->ed->seqbase, sound); diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c index d2e4025bdfc..ba080a07879 100644 --- a/source/blender/sequencer/intern/strip_add.c +++ b/source/blender/sequencer/intern/strip_add.c @@ -53,7 +53,13 @@ #include "IMB_imbuf_types.h" #include "IMB_metadata.h" +#include "SEQ_add.h" +#include "SEQ_relations.h" +#include "SEQ_select.h" #include "SEQ_sequencer.h" +#include "SEQ_time.h" +#include "SEQ_transform.h" +#include "SEQ_utils.h" #include "multiview.h" #include "proxy.h" @@ -64,7 +70,7 @@ static void seq_load_apply(Main *bmain, Scene *scene, Sequence *seq, SeqLoadInfo if (seq) { BLI_strncpy_utf8(seq->name + 2, seq_load->name, sizeof(seq->name) - 2); BLI_utf8_invalid_strip(seq->name + 2, strlen(seq->name + 2)); - BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq); + SEQ_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq); if (seq_load->flag & SEQ_LOAD_FRAME_ADVANCE) { seq_load->start_frame += (seq->enddisp - seq->startdisp); @@ -72,7 +78,7 @@ static void seq_load_apply(Main *bmain, Scene *scene, Sequence *seq, SeqLoadInfo if (seq_load->flag & SEQ_LOAD_REPLACE_SEL) { seq_load->flag |= SELECT; - BKE_sequencer_active_set(scene, seq); + SEQ_select_active_set(scene, seq); } if (seq_load->flag & SEQ_LOAD_SOUND_MONO) { @@ -94,13 +100,13 @@ static void seq_load_apply(Main *bmain, Scene *scene, Sequence *seq, SeqLoadInfo } /* NOTE: this function doesn't fill in image names */ -Sequence *BKE_sequencer_add_image_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load) +Sequence *SEQ_add_image_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load) { Scene *scene = CTX_data_scene(C); /* only for active seq */ Sequence *seq; Strip *strip; - seq = BKE_sequence_alloc(seqbasep, seq_load->start_frame, seq_load->channel, SEQ_TYPE_IMAGE); + seq = SEQ_sequence_alloc(seqbasep, seq_load->start_frame, seq_load->channel, SEQ_TYPE_IMAGE); seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */ /* basic defaults */ @@ -118,17 +124,28 @@ Sequence *BKE_sequencer_add_image_strip(bContext *C, ListBase *seqbasep, SeqLoad seq->flag |= seq_load->flag & SEQ_USE_VIEWS; seq_load_apply(CTX_data_main(C), scene, seq, seq_load); - BKE_sequence_invalidate_cache_composite(scene, seq); + + char file_path[FILE_MAX]; + BLI_join_dirfile(file_path, sizeof(file_path), seq_load->path, seq_load->name); + BLI_path_abs(file_path, BKE_main_blendfile_path(CTX_data_main(C))); + ImBuf *ibuf = IMB_loadiffname(file_path, IB_rect, seq->strip->colorspace_settings.name); + if (ibuf != NULL) { + SEQ_set_scale_to_fit( + seq, ibuf->x, ibuf->y, scene->r.xsch, scene->r.ysch, seq_load->fit_method); + IMB_freeImBuf(ibuf); + } + + SEQ_relations_invalidate_cache_composite(scene, seq); return seq; } #ifdef WITH_AUDASPACE -Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load) +Sequence *SEQ_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); /* only for sound */ - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); bSound *sound; Sequence *seq; /* generic strip vars */ @@ -148,10 +165,10 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad return NULL; } - seq = BKE_sequence_alloc(seqbasep, seq_load->start_frame, seq_load->channel, SEQ_TYPE_SOUND_RAM); + seq = SEQ_sequence_alloc(seqbasep, seq_load->start_frame, seq_load->channel, SEQ_TYPE_SOUND_RAM); seq->sound = sound; BLI_strncpy(seq->name + 2, "Sound", SEQ_NAME_MAXSTR - 2); - BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq); + SEQ_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq); /* basic defaults */ /* We add a very small negative offset here, because @@ -166,7 +183,7 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad seq->scene_sound = NULL; - BKE_sequence_calc_disp(scene, seq); + SEQ_time_update_sequence_bounds(scene, seq); /* last active name */ BLI_strncpy(ed->act_sounddir, strip->dir, FILE_MAXDIR); @@ -179,7 +196,7 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad return seq; } #else // WITH_AUDASPACE -Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load) +Sequence *SEQ_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load) { (void)C; (void)seqbasep; @@ -188,7 +205,7 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad } #endif // WITH_AUDASPACE -Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load) +Sequence *SEQ_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); /* only for sound */ @@ -249,7 +266,7 @@ Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoad if (seq_load->flag & SEQ_LOAD_MOVIE_SOUND) { seq_load->channel++; } - seq = BKE_sequence_alloc(seqbasep, seq_load->start_frame, seq_load->channel, SEQ_TYPE_MOVIE); + seq = SEQ_sequence_alloc(seqbasep, seq_load->start_frame, seq_load->channel, SEQ_TYPE_MOVIE); /* multiview settings */ if (seq_load->stereo3d_format) { @@ -275,8 +292,13 @@ Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoad IMB_anim_load_metadata(anim_arr[0]); seq->anim_preseek = IMB_anim_get_preseek(anim_arr[0]); + + const float width = IMB_anim_get_image_width(anim_arr[0]); + const float height = IMB_anim_get_image_height(anim_arr[0]); + SEQ_set_scale_to_fit(seq, width, height, scene->r.xsch, scene->r.ysch, seq_load->fit_method); + BLI_strncpy(seq->name + 2, "Movie", SEQ_NAME_MAXSTR - 2); - BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq); + SEQ_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq); /* adjust scene's frame rate settings to match */ if (seq_load->flag & SEQ_LOAD_SYNC_FPS) { @@ -296,7 +318,7 @@ Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoad BLI_split_dirfile(seq_load->path, strip->dir, se->name, sizeof(strip->dir), sizeof(se->name)); - BKE_sequence_calc_disp(scene, seq); + SEQ_time_update_sequence_bounds(scene, seq); if (seq_load->name[0] == '\0') { BLI_strncpy(seq_load->name, se->name, sizeof(seq_load->name)); @@ -305,20 +327,20 @@ Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoad if (seq_load->flag & SEQ_LOAD_MOVIE_SOUND) { int start_frame_back = seq_load->start_frame; seq_load->channel--; - seq_load->seq_sound = BKE_sequencer_add_sound_strip(C, seqbasep, seq_load); + seq_load->seq_sound = SEQ_add_sound_strip(C, seqbasep, seq_load); seq_load->start_frame = start_frame_back; } /* can be NULL */ seq_load_apply(CTX_data_main(C), scene, seq, seq_load); - BKE_sequence_invalidate_cache_composite(scene, seq); + SEQ_relations_invalidate_cache_composite(scene, seq); MEM_freeN(anim_arr); return seq; } -/* note: caller should run BKE_sequence_calc(scene, seq) after */ -void BKE_sequence_reload_new_file(Main *bmain, Scene *scene, Sequence *seq, const bool lock_range) +/* note: caller should run SEQ_time_update_sequence(scene, seq) after */ +void SEQ_add_reload_new_file(Main *bmain, Scene *scene, Sequence *seq, const bool lock_range) { char path[FILE_MAX]; int prev_startdisp = 0, prev_enddisp = 0; @@ -337,7 +359,7 @@ void BKE_sequence_reload_new_file(Main *bmain, Scene *scene, Sequence *seq, cons if (lock_range) { /* keep so we don't have to move the actual start and end points (only the data) */ - BKE_sequence_calc_disp(scene, seq); + SEQ_time_update_sequence_bounds(scene, seq); prev_startdisp = seq->startdisp; prev_enddisp = seq->enddisp; } @@ -364,7 +386,7 @@ void BKE_sequence_reload_new_file(Main *bmain, Scene *scene, Sequence *seq, cons BLI_join_dirfile(path, sizeof(path), seq->strip->dir, seq->strip->stripdata->name); BLI_path_abs(path, BKE_main_blendfile_path_from_global()); - BKE_sequence_free_anim(seq); + SEQ_relations_sequence_free_anim(seq); if (is_multiview && (seq->views_format == R_IMF_VIEWS_INDIVIDUAL)) { char prefix[FILE_MAX]; @@ -484,19 +506,19 @@ void BKE_sequence_reload_new_file(Main *bmain, Scene *scene, Sequence *seq, cons free_proxy_seq(seq); if (lock_range) { - BKE_sequence_tx_set_final_left(seq, prev_startdisp); - BKE_sequence_tx_set_final_right(seq, prev_enddisp); - BKE_sequence_single_fix(seq); + SEQ_transform_set_left_handle_frame(seq, prev_startdisp); + SEQ_transform_set_right_handle_frame(seq, prev_enddisp); + SEQ_transform_fix_single_image_seq_offsets(seq); } - BKE_sequence_calc(scene, seq); + SEQ_time_update_sequence(scene, seq); } -void BKE_sequence_movie_reload_if_needed(struct Main *bmain, - struct Scene *scene, - struct Sequence *seq, - bool *r_was_reloaded, - bool *r_can_produce_frames) +void SEQ_add_movie_reload_if_needed(struct Main *bmain, + struct Scene *scene, + struct Sequence *seq, + bool *r_was_reloaded, + bool *r_can_produce_frames) { BLI_assert(seq->type == SEQ_TYPE_MOVIE || !"This function is only implemented for movie strips."); @@ -528,7 +550,7 @@ void BKE_sequence_movie_reload_if_needed(struct Main *bmain, return; } - BKE_sequence_reload_new_file(bmain, scene, seq, true); + SEQ_add_reload_new_file(bmain, scene, seq, true); *r_was_reloaded = true; if (BLI_listbase_is_empty(&seq->anims)) { diff --git a/source/blender/sequencer/intern/strip_edit.c b/source/blender/sequencer/intern/strip_edit.c index 3137a471470..bba026057d2 100644 --- a/source/blender/sequencer/intern/strip_edit.c +++ b/source/blender/sequencer/intern/strip_edit.c @@ -38,9 +38,16 @@ #include "BKE_scene.h" #include "BKE_sound.h" +#include "strip_time.h" + +#include "SEQ_add.h" +#include "SEQ_edit.h" +#include "SEQ_effects.h" #include "SEQ_sequencer.h" +#include "SEQ_time.h" +#include "SEQ_transform.h" -int BKE_sequence_swap(Sequence *seq_a, Sequence *seq_b, const char **error_str) +int SEQ_edit_sequence_swap(Sequence *seq_a, Sequence *seq_b, const char **error_str) { char name[sizeof(seq_a->name)]; @@ -63,8 +70,7 @@ int BKE_sequence_swap(Sequence *seq_a, Sequence *seq_b, const char **error_str) } if ((seq_a->type & SEQ_TYPE_EFFECT) && (seq_b->type & SEQ_TYPE_EFFECT)) { - if (BKE_sequence_effect_get_num_inputs(seq_a->type) != - BKE_sequence_effect_get_num_inputs(seq_b->type)) { + if (SEQ_effect_get_num_inputs(seq_a->type) != SEQ_effect_get_num_inputs(seq_b->type)) { *error_str = N_("Strips must have the same number of inputs"); return 0; } @@ -123,7 +129,7 @@ static void seq_update_muting_recursive(ListBase *seqbasep, Sequence *metaseq, i } } -void BKE_sequencer_update_muting(Editing *ed) +void SEQ_edit_update_muting(Editing *ed) { if (ed) { /* mute all sounds up to current metastack list */ @@ -165,7 +171,7 @@ static void sequencer_flag_users_for_removal(Scene *scene, ListBase *seqbase, Se } /* Flag seq and its users (effects) for removal. */ -void BKE_sequencer_flag_for_removal(Scene *scene, ListBase *seqbase, Sequence *seq) +void SEQ_edit_flag_for_removal(Scene *scene, ListBase *seqbase, Sequence *seq) { if (seq == NULL || (seq->flag & SEQ_FLAG_DELETE) != 0) { return; @@ -174,7 +180,7 @@ void BKE_sequencer_flag_for_removal(Scene *scene, ListBase *seqbase, Sequence *s /* Flag and remove meta children. */ if (seq->type == SEQ_TYPE_META) { LISTBASE_FOREACH (Sequence *, meta_child, &seq->seqbase) { - BKE_sequencer_flag_for_removal(scene, &seq->seqbase, meta_child); + SEQ_edit_flag_for_removal(scene, &seq->seqbase, meta_child); } } @@ -183,15 +189,15 @@ void BKE_sequencer_flag_for_removal(Scene *scene, ListBase *seqbase, Sequence *s } /* Remove all flagged sequences, return true if sequence is removed. */ -void BKE_sequencer_remove_flagged_sequences(Scene *scene, ListBase *seqbase) +void SEQ_edit_remove_flagged_sequences(Scene *scene, ListBase *seqbase) { LISTBASE_FOREACH_MUTABLE (Sequence *, seq, seqbase) { if (seq->flag & SEQ_FLAG_DELETE) { if (seq->type == SEQ_TYPE_META) { - BKE_sequencer_remove_flagged_sequences(scene, &seq->seqbase); + SEQ_edit_remove_flagged_sequences(scene, &seq->seqbase); } BLI_remlink(seqbase, seq); - BKE_sequence_free(scene, seq, true); + SEQ_sequence_free(scene, seq, true); } } } @@ -252,7 +258,7 @@ static void seq_split_set_right_offset(Sequence *seq, int timeline_frame) else if ((seq->start + seq->len) < timeline_frame) { seq->endstill -= seq->enddisp - timeline_frame; } - BKE_sequence_tx_set_final_right(seq, timeline_frame); + SEQ_transform_set_right_handle_frame(seq, timeline_frame); } static void seq_split_set_left_offset(Sequence *seq, int timeline_frame) @@ -266,7 +272,7 @@ static void seq_split_set_left_offset(Sequence *seq, int timeline_frame) seq->start = timeline_frame - seq->len + 1; seq->endstill = seq->enddisp - timeline_frame - 1; } - BKE_sequence_tx_set_final_left(seq, timeline_frame); + SEQ_transform_set_left_handle_frame(seq, timeline_frame); } /** @@ -295,12 +301,12 @@ Sequence *SEQ_edit_strip_split(Main *bmain, /* Precaution, needed because the length saved on-disk may not match the length saved in the * blend file, or our code may have minor differences reading file length between versions. * This causes hard-split to fail, see: T47862. */ - BKE_sequence_reload_new_file(bmain, scene, seq, true); - BKE_sequence_calc(scene, seq); + SEQ_add_reload_new_file(bmain, scene, seq, true); + SEQ_time_update_sequence(scene, seq); } Sequence *left_seq = seq; - Sequence *right_seq = BKE_sequence_dupli_recursive( + Sequence *right_seq = SEQ_sequence_dupli_recursive( scene, scene, seqbase, seq, SEQ_DUPE_UNIQUE_NAME | SEQ_DUPE_ANIM); switch (method) { @@ -311,11 +317,46 @@ Sequence *SEQ_edit_strip_split(Main *bmain, case SEQ_SPLIT_HARD: seq_split_set_right_hold_offset(left_seq, timeline_frame); seq_split_set_left_hold_offset(right_seq, timeline_frame); - BKE_sequence_reload_new_file(bmain, scene, left_seq, false); - BKE_sequence_reload_new_file(bmain, scene, right_seq, false); + SEQ_add_reload_new_file(bmain, scene, left_seq, false); + SEQ_add_reload_new_file(bmain, scene, right_seq, false); break; } - BKE_sequence_calc(scene, left_seq); - BKE_sequence_calc(scene, right_seq); + SEQ_time_update_sequence(scene, left_seq); + SEQ_time_update_sequence(scene, right_seq); return right_seq; } + +/** + * Find gap after initial_frame and move strips on right side to close the gap + * + * \param scene: Scene in which strips are located + * \param seqbase: ListBase in which strips are located + * \param initial_frame: frame on timeline from where gaps are searched for + * \param remove_all_gaps: remove all gaps instead of one gap + * \return true if gap is removed, otherwise false + */ +bool SEQ_edit_remove_gaps(Scene *scene, + ListBase *seqbase, + const int initial_frame, + const bool remove_all_gaps) +{ + GapInfo gap_info = {0}; + seq_time_gap_info_get(scene, seqbase, initial_frame, &gap_info); + + if (!gap_info.gap_exists) { + return false; + } + + if (remove_all_gaps) { + while (gap_info.gap_exists) { + SEQ_transform_offset_after_frame( + scene, seqbase, -gap_info.gap_length, gap_info.gap_start_frame); + seq_time_gap_info_get(scene, seqbase, initial_frame, &gap_info); + } + } + else { + SEQ_transform_offset_after_frame( + scene, seqbase, -gap_info.gap_length, gap_info.gap_start_frame); + } + return true; +} diff --git a/source/blender/sequencer/intern/strip_relations.c b/source/blender/sequencer/intern/strip_relations.c index d802ce22f21..18ae21e3a65 100644 --- a/source/blender/sequencer/intern/strip_relations.c +++ b/source/blender/sequencer/intern/strip_relations.c @@ -40,14 +40,18 @@ #include "IMB_imbuf.h" +#include "SEQ_iterator.h" +#include "SEQ_prefetch.h" +#include "SEQ_relations.h" #include "SEQ_sequencer.h" +#include "SEQ_time.h" #include "effects.h" #include "image_cache.h" #include "utils.h" /* check whether sequence cur depends on seq */ -static bool BKE_sequence_check_depend(Sequence *seq, Sequence *cur) +static bool seq_relations_check_depend(Sequence *seq, Sequence *cur) { if (cur->seq1 == seq || cur->seq2 == seq || cur->seq3 == seq) { return true; @@ -84,14 +88,14 @@ static void sequence_do_invalidate_dependent(Scene *scene, Sequence *seq, ListBa continue; } - if (BKE_sequence_check_depend(seq, cur)) { + if (seq_relations_check_depend(seq, cur)) { /* Effect must be invalidated completely if they depend on invalidated seq. */ if ((cur->type & SEQ_TYPE_EFFECT) != 0) { - BKE_sequencer_cache_cleanup_sequence(scene, cur, seq, SEQ_CACHE_ALL_TYPES, false); + seq_cache_cleanup_sequence(scene, cur, seq, SEQ_CACHE_ALL_TYPES, false); } else { /* In case of alpha over for example only invalidate composite image */ - BKE_sequencer_cache_cleanup_sequence( + seq_cache_cleanup_sequence( scene, cur, seq, SEQ_CACHE_STORE_COMPOSITE | SEQ_CACHE_STORE_FINAL_OUT, false); } } @@ -110,33 +114,33 @@ static void sequence_invalidate_cache(Scene *scene, Editing *ed = scene->ed; if (invalidate_self) { - BKE_sequence_free_anim(seq); - BKE_sequencer_cache_cleanup_sequence(scene, seq, seq, invalidate_types, false); + SEQ_relations_sequence_free_anim(seq); + seq_cache_cleanup_sequence(scene, seq, seq, invalidate_types, false); } if (seq->effectdata && seq->type == SEQ_TYPE_SPEED) { - BKE_sequence_effect_speed_rebuild_map(scene, seq, true); + seq_effect_speed_rebuild_map(scene, seq, true); } sequence_do_invalidate_dependent(scene, seq, &ed->seqbase); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); - BKE_sequencer_prefetch_stop(scene); + SEQ_prefetch_stop(scene); } -void BKE_sequence_invalidate_cache_in_range(Scene *scene, - Sequence *seq, - Sequence *range_mask, - int invalidate_types) +void SEQ_relations_invalidate_cache_in_range(Scene *scene, + Sequence *seq, + Sequence *range_mask, + int invalidate_types) { - BKE_sequencer_cache_cleanup_sequence(scene, seq, range_mask, invalidate_types, true); + seq_cache_cleanup_sequence(scene, seq, range_mask, invalidate_types, true); } -void BKE_sequence_invalidate_cache_raw(Scene *scene, Sequence *seq) +void SEQ_relations_invalidate_cache_raw(Scene *scene, Sequence *seq) { sequence_invalidate_cache(scene, seq, true, SEQ_CACHE_ALL_TYPES); } -void BKE_sequence_invalidate_cache_preprocessed(Scene *scene, Sequence *seq) +void SEQ_relations_invalidate_cache_preprocessed(Scene *scene, Sequence *seq) { sequence_invalidate_cache(scene, seq, @@ -145,7 +149,7 @@ void BKE_sequence_invalidate_cache_preprocessed(Scene *scene, Sequence *seq) SEQ_CACHE_STORE_FINAL_OUT); } -void BKE_sequence_invalidate_cache_composite(Scene *scene, Sequence *seq) +void SEQ_relations_invalidate_cache_composite(Scene *scene, Sequence *seq) { if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) { return; @@ -155,7 +159,7 @@ void BKE_sequence_invalidate_cache_composite(Scene *scene, Sequence *seq) scene, seq, true, SEQ_CACHE_STORE_COMPOSITE | SEQ_CACHE_STORE_FINAL_OUT); } -void BKE_sequence_invalidate_dependent(Scene *scene, Sequence *seq) +void SEQ_relations_invalidate_dependent(Scene *scene, Sequence *seq) { if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) { return; @@ -169,7 +173,7 @@ static void invalidate_scene_strips(Scene *scene, Scene *scene_target, ListBase { for (Sequence *seq = seqbase->first; seq != NULL; seq = seq->next) { if (seq->scene == scene_target) { - BKE_sequence_invalidate_cache_raw(scene, seq); + SEQ_relations_invalidate_cache_raw(scene, seq); } if (seq->seqbase.first != NULL) { @@ -178,7 +182,7 @@ static void invalidate_scene_strips(Scene *scene, Scene *scene_target, ListBase } } -void BKE_sequence_invalidate_scene_strips(Main *bmain, Scene *scene_target) +void SEQ_relations_invalidate_scene_strips(Main *bmain, Scene *scene_target) { for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) { if (scene->ed != NULL) { @@ -191,7 +195,7 @@ static void invalidate_movieclip_strips(Scene *scene, MovieClip *clip_target, Li { for (Sequence *seq = seqbase->first; seq != NULL; seq = seq->next) { if (seq->clip == clip_target) { - BKE_sequence_invalidate_cache_raw(scene, seq); + SEQ_relations_invalidate_cache_raw(scene, seq); } if (seq->seqbase.first != NULL) { @@ -200,7 +204,7 @@ static void invalidate_movieclip_strips(Scene *scene, MovieClip *clip_target, Li } } -void BKE_sequence_invalidate_movieclip_strips(Main *bmain, MovieClip *clip_target) +void SEQ_relations_invalidate_movieclip_strips(Main *bmain, MovieClip *clip_target) { for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) { if (scene->ed != NULL) { @@ -209,7 +213,7 @@ void BKE_sequence_invalidate_movieclip_strips(Main *bmain, MovieClip *clip_targe } } -void BKE_sequencer_free_imbuf(Scene *scene, ListBase *seqbase, bool for_render) +void SEQ_relations_free_imbuf(Scene *scene, ListBase *seqbase, bool for_render) { if (scene->ed == NULL) { return; @@ -217,8 +221,8 @@ void BKE_sequencer_free_imbuf(Scene *scene, ListBase *seqbase, bool for_render) Sequence *seq; - BKE_sequencer_cache_cleanup(scene); - BKE_sequencer_prefetch_stop(scene); + SEQ_cache_cleanup(scene); + SEQ_prefetch_stop(scene); for (seq = seqbase->first; seq; seq = seq->next) { if (for_render && CFRA >= seq->startdisp && CFRA <= seq->enddisp) { @@ -227,14 +231,14 @@ void BKE_sequencer_free_imbuf(Scene *scene, ListBase *seqbase, bool for_render) if (seq->strip) { if (seq->type == SEQ_TYPE_MOVIE) { - BKE_sequence_free_anim(seq); + SEQ_relations_sequence_free_anim(seq); } if (seq->type == SEQ_TYPE_SPEED) { - BKE_sequence_effect_speed_rebuild_map(scene, seq, true); + seq_effect_speed_rebuild_map(scene, seq, true); } } if (seq->type == SEQ_TYPE_META) { - BKE_sequencer_free_imbuf(scene, &seq->seqbase, for_render); + SEQ_relations_free_imbuf(scene, &seq->seqbase, for_render); } if (seq->type == SEQ_TYPE_SCENE) { /* FIXME: recurse downwards, @@ -284,27 +288,27 @@ static bool update_changed_seq_recurs( if (free_imbuf) { if (ibuf_change) { if (seq->type == SEQ_TYPE_MOVIE) { - BKE_sequence_free_anim(seq); + SEQ_relations_sequence_free_anim(seq); } else if (seq->type == SEQ_TYPE_SPEED) { - BKE_sequence_effect_speed_rebuild_map(scene, seq, true); + seq_effect_speed_rebuild_map(scene, seq, true); } } if (len_change) { - BKE_sequence_calc(scene, seq); + SEQ_time_update_sequence(scene, seq); } } return free_imbuf; } -void BKE_sequencer_update_changed_seq_and_deps(Scene *scene, +void SEQ_relations_update_changed_seq_and_deps(Scene *scene, Sequence *changed_seq, int len_change, int ibuf_change) { - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq; if (ed == NULL) { @@ -321,7 +325,7 @@ static void sequencer_all_free_anim_ibufs(ListBase *seqbase, int timeline_frame) { for (Sequence *seq = seqbase->first; seq != NULL; seq = seq->next) { if (seq->enddisp < timeline_frame || seq->startdisp > timeline_frame) { - BKE_sequence_free_anim(seq); + SEQ_relations_sequence_free_anim(seq); } if (seq->type == SEQ_TYPE_META) { sequencer_all_free_anim_ibufs(&seq->seqbase, timeline_frame); @@ -330,14 +334,14 @@ static void sequencer_all_free_anim_ibufs(ListBase *seqbase, int timeline_frame) } /* Unused */ -void BKE_sequencer_all_free_anim_ibufs(Scene *scene, int timeline_frame) +void SEQ_relations_free_all_anim_ibufs(Scene *scene, int timeline_frame) { - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (ed == NULL) { return; } sequencer_all_free_anim_ibufs(&ed->seqbase, timeline_frame); - BKE_sequencer_cache_cleanup(scene); + SEQ_cache_cleanup(scene); } static Sequence *sequencer_check_scene_recursion(Scene *scene, ListBase *seqbase) @@ -361,9 +365,9 @@ static Sequence *sequencer_check_scene_recursion(Scene *scene, ListBase *seqbase return NULL; } -bool BKE_sequencer_check_scene_recursion(Scene *scene, ReportList *reports) +bool SEQ_relations_check_scene_recursion(Scene *scene, ReportList *reports) { - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (ed == NULL) { return false; } @@ -391,7 +395,7 @@ bool BKE_sequencer_check_scene_recursion(Scene *scene, ReportList *reports) } /* Check if "seq_main" (indirectly) uses strip "seq". */ -bool BKE_sequencer_render_loop_check(Sequence *seq_main, Sequence *seq) +bool SEQ_relations_render_loop_check(Sequence *seq_main, Sequence *seq) { if (seq_main == NULL || seq == NULL) { return false; @@ -401,15 +405,15 @@ bool BKE_sequencer_render_loop_check(Sequence *seq_main, Sequence *seq) return true; } - if ((seq_main->seq1 && BKE_sequencer_render_loop_check(seq_main->seq1, seq)) || - (seq_main->seq2 && BKE_sequencer_render_loop_check(seq_main->seq2, seq)) || - (seq_main->seq3 && BKE_sequencer_render_loop_check(seq_main->seq3, seq))) { + if ((seq_main->seq1 && SEQ_relations_render_loop_check(seq_main->seq1, seq)) || + (seq_main->seq2 && SEQ_relations_render_loop_check(seq_main->seq2, seq)) || + (seq_main->seq3 && SEQ_relations_render_loop_check(seq_main->seq3, seq))) { return true; } SequenceModifierData *smd; for (smd = seq_main->modifiers.first; smd; smd = smd->next) { - if (smd->mask_sequence && BKE_sequencer_render_loop_check(smd->mask_sequence, seq)) { + if (smd->mask_sequence && SEQ_relations_render_loop_check(smd->mask_sequence, seq)) { return true; } } @@ -418,7 +422,7 @@ bool BKE_sequencer_render_loop_check(Sequence *seq_main, Sequence *seq) } /* Function to free imbuf and anim data on changes */ -void BKE_sequence_free_anim(Sequence *seq) +void SEQ_relations_sequence_free_anim(Sequence *seq) { while (seq->anims.last) { StripAnim *sanim = seq->anims.last; @@ -433,12 +437,12 @@ void BKE_sequence_free_anim(Sequence *seq) BLI_listbase_clear(&seq->anims); } -void BKE_sequence_session_uuid_generate(struct Sequence *sequence) +void SEQ_relations_session_uuid_generate(struct Sequence *sequence) { sequence->runtime.session_uuid = BLI_session_uuid_generate(); } -void BKE_sequencer_check_uuids_unique_and_report(const Scene *scene) +void SEQ_relations_check_uuids_unique_and_report(const Scene *scene) { if (scene->ed == NULL) { return; diff --git a/source/blender/sequencer/intern/strip_select.c b/source/blender/sequencer/intern/strip_select.c index 478ae9be337..58ae281ead1 100644 --- a/source/blender/sequencer/intern/strip_select.c +++ b/source/blender/sequencer/intern/strip_select.c @@ -29,11 +29,12 @@ #include "BKE_scene.h" +#include "SEQ_select.h" #include "SEQ_sequencer.h" -Sequence *BKE_sequencer_active_get(Scene *scene) +Sequence *SEQ_select_active_get(Scene *scene) { - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (ed == NULL) { return NULL; @@ -42,9 +43,9 @@ Sequence *BKE_sequencer_active_get(Scene *scene) return ed->act_seq; } -void BKE_sequencer_active_set(Scene *scene, Sequence *seq) +void SEQ_select_active_set(Scene *scene, Sequence *seq) { - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); if (ed == NULL) { return; @@ -53,11 +54,11 @@ void BKE_sequencer_active_set(Scene *scene, Sequence *seq) ed->act_seq = seq; } -int BKE_sequencer_active_get_pair(Scene *scene, Sequence **seq_act, Sequence **seq_other) +int SEQ_select_active_get_pair(Scene *scene, Sequence **seq_act, Sequence **seq_other) { - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); - *seq_act = BKE_sequencer_active_get(scene); + *seq_act = SEQ_select_active_get(scene); if (*seq_act == NULL) { return 0; diff --git a/source/blender/sequencer/intern/strip_time.c b/source/blender/sequencer/intern/strip_time.c index a0ae6d6f16d..c495ad6d8f1 100644 --- a/source/blender/sequencer/intern/strip_time.c +++ b/source/blender/sequencer/intern/strip_time.c @@ -36,7 +36,9 @@ #include "IMB_imbuf.h" +#include "SEQ_render.h" #include "SEQ_sequencer.h" +#include "SEQ_time.h" #include "strip_time.h" #include "utils.h" @@ -142,7 +144,7 @@ void seq_update_sound_bounds_recursive(Scene *scene, Sequence *metaseq) scene, metaseq, metaseq_start(metaseq), metaseq_end(metaseq)); } -void BKE_sequence_calc_disp(Scene *scene, Sequence *seq) +void SEQ_time_update_sequence_bounds(Scene *scene, Sequence *seq) { if (seq->startofs && seq->startstill) { seq->startstill = 0; @@ -159,7 +161,7 @@ void BKE_sequence_calc_disp(Scene *scene, Sequence *seq) } } -void BKE_sequence_calc(Scene *scene, Sequence *seq) +void SEQ_time_update_sequence(Scene *scene, Sequence *seq) { Sequence *seqm; int min, max; @@ -168,7 +170,7 @@ void BKE_sequence_calc(Scene *scene, Sequence *seq) seqm = seq->seqbase.first; while (seqm) { if (seqm->seqbase.first) { - BKE_sequence_calc(scene, seqm); + SEQ_time_update_sequence(scene, seqm); } seqm = seqm->next; } @@ -206,7 +208,7 @@ void BKE_sequence_calc(Scene *scene, Sequence *seq) seq->len = seq->enddisp - seq->startdisp; } else { - BKE_sequence_calc_disp(scene, seq); + SEQ_time_update_sequence_bounds(scene, seq); } } else { @@ -231,12 +233,12 @@ void BKE_sequence_calc(Scene *scene, Sequence *seq) } seq_update_sound_bounds_recursive(scene, seq); } - BKE_sequence_calc_disp(scene, seq); + SEQ_time_update_sequence_bounds(scene, seq); } } /** Comparison function suitable to be used with BLI_listbase_sort()... */ -int BKE_sequencer_cmp_time_startdisp(const void *a, const void *b) +int SEQ_time_cmp_time_startdisp(const void *a, const void *b) { const Sequence *seq_a = a; const Sequence *seq_b = b; @@ -244,14 +246,14 @@ int BKE_sequencer_cmp_time_startdisp(const void *a, const void *b) return (seq_a->startdisp > seq_b->startdisp); } -int BKE_sequencer_find_next_prev_edit(Scene *scene, - int timeline_frame, - const short side, - const bool do_skip_mute, - const bool do_center, - const bool do_unselected) +int SEQ_time_find_next_prev_edit(Scene *scene, + int timeline_frame, + const short side, + const bool do_skip_mute, + const bool do_center, + const bool do_unselected) { - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq; int dist, best_dist, best_frame = timeline_frame; @@ -319,7 +321,7 @@ int BKE_sequencer_find_next_prev_edit(Scene *scene, return best_frame; } -float BKE_sequence_get_fps(Scene *scene, Sequence *seq) +float SEQ_time_sequence_get_fps(Scene *scene, Sequence *seq) { switch (seq->type) { case SEQ_TYPE_MOVIE: { @@ -351,3 +353,85 @@ float BKE_sequence_get_fps(Scene *scene, Sequence *seq) } return 0.0f; } + +/** + * Define boundary rectangle of sequencer timeline and fill in rect data + * + * \param scene: Scene in which strips are located + * \param seqbase: ListBase in which strips are located + * \param rect: data structure describing rectangle, that will be filled in by this function + */ +void SEQ_timeline_boundbox(const Scene *scene, const ListBase *seqbase, rctf *rect) +{ + rect->xmin = scene->r.sfra; + rect->xmax = scene->r.efra + 1; + rect->ymin = 0.0f; + rect->ymax = 8.0f; + + if (seqbase == NULL) { + return; + } + + LISTBASE_FOREACH (Sequence *, seq, seqbase) { + if (rect->xmin > seq->startdisp - 1) { + rect->xmin = seq->startdisp - 1; + } + if (rect->xmax < seq->enddisp + 1) { + rect->xmax = seq->enddisp + 1; + } + if (rect->ymax < seq->machine + 2) { + rect->ymax = seq->machine + 2; + } + } +} + +/** + * Find first gap between strips after initial_frame and describe it by filling data of r_gap_info + * + * \param scene: Scene in which strips are located + * \param seqbase: ListBase in which strips are located + * \param initial_frame: frame on timeline from where gaps are searched for + * \param r_gap_info: data structure describing gap, that will be filled in by this function + */ +void seq_time_gap_info_get(const Scene *scene, + ListBase *seqbase, + const int initial_frame, + GapInfo *r_gap_info) +{ + rctf rectf; + /* Get first and last frame. */ + SEQ_timeline_boundbox(scene, seqbase, &rectf); + const int sfra = (int)rectf.xmin; + const int efra = (int)rectf.xmax; + int timeline_frame = initial_frame; + r_gap_info->gap_exists = false; + + if (SEQ_render_evaluate_frame(seqbase, initial_frame) == 0) { + /* Search backward for gap_start_frame. */ + for (; timeline_frame >= sfra; timeline_frame--) { + if (SEQ_render_evaluate_frame(seqbase, timeline_frame) != 0) { + break; + } + } + r_gap_info->gap_start_frame = timeline_frame + 1; + timeline_frame = initial_frame; + } + else { + /* Search forward for gap_start_frame. */ + for (; timeline_frame <= efra; timeline_frame++) { + if (SEQ_render_evaluate_frame(seqbase, timeline_frame) == 0) { + r_gap_info->gap_start_frame = timeline_frame; + break; + } + } + } + /* Search forward for gap_end_frame. */ + for (; timeline_frame <= efra; timeline_frame++) { + if (SEQ_render_evaluate_frame(seqbase, timeline_frame) != 0) { + const int gap_end_frame = timeline_frame; + r_gap_info->gap_length = gap_end_frame - r_gap_info->gap_start_frame; + r_gap_info->gap_exists = true; + break; + } + } +} diff --git a/source/blender/sequencer/intern/strip_time.h b/source/blender/sequencer/intern/strip_time.h index e4fb7f1d2ec..ca9a935bc96 100644 --- a/source/blender/sequencer/intern/strip_time.h +++ b/source/blender/sequencer/intern/strip_time.h @@ -27,12 +27,24 @@ extern "C" { #endif +struct ListBase; struct Scene; struct Sequence; float seq_give_frame_index(struct Sequence *seq, float timeline_frame); void seq_update_sound_bounds_recursive(struct Scene *scene, struct Sequence *metaseq); +/* Describes gap between strips in timeline. */ +typedef struct GapInfo { + int gap_start_frame; /* Start frame of the gap. */ + int gap_length; /* Length of the gap. */ + bool gap_exists; /* False if there are no gaps. */ +} GapInfo; +void seq_time_gap_info_get(const struct Scene *scene, + struct ListBase *seqbase, + const int initial_frame, + struct GapInfo *r_gap_info); + #ifdef __cplusplus } #endif diff --git a/source/blender/sequencer/intern/strip_transform.c b/source/blender/sequencer/intern/strip_transform.c index 233f8e5b22e..3a0ba36b795 100644 --- a/source/blender/sequencer/intern/strip_transform.c +++ b/source/blender/sequencer/intern/strip_transform.c @@ -33,7 +33,11 @@ #include "BKE_scene.h" #include "BKE_sound.h" +#include "SEQ_effects.h" +#include "SEQ_relations.h" #include "SEQ_sequencer.h" +#include "SEQ_time.h" +#include "SEQ_transform.h" static int seq_tx_get_start(Sequence *seq) { @@ -44,28 +48,28 @@ static int seq_tx_get_end(Sequence *seq) return seq->start + seq->len; } -int BKE_sequence_tx_get_final_left(Sequence *seq, bool metaclip) +int SEQ_transform_get_left_handle_frame(Sequence *seq, bool metaclip) { if (metaclip && seq->tmp) { /* return the range clipped by the parents range */ - return max_ii(BKE_sequence_tx_get_final_left(seq, false), - BKE_sequence_tx_get_final_left((Sequence *)seq->tmp, true)); + return max_ii(SEQ_transform_get_left_handle_frame(seq, false), + SEQ_transform_get_left_handle_frame((Sequence *)seq->tmp, true)); } return (seq->start - seq->startstill) + seq->startofs; } -int BKE_sequence_tx_get_final_right(Sequence *seq, bool metaclip) +int SEQ_transform_get_right_handle_frame(Sequence *seq, bool metaclip) { if (metaclip && seq->tmp) { /* return the range clipped by the parents range */ - return min_ii(BKE_sequence_tx_get_final_right(seq, false), - BKE_sequence_tx_get_final_right((Sequence *)seq->tmp, true)); + return min_ii(SEQ_transform_get_right_handle_frame(seq, false), + SEQ_transform_get_right_handle_frame((Sequence *)seq->tmp, true)); } return ((seq->start + seq->len) + seq->endstill) - seq->endofs; } -void BKE_sequence_tx_set_final_left(Sequence *seq, int val) +void SEQ_transform_set_left_handle_frame(Sequence *seq, int val) { if (val < (seq)->start) { seq->startstill = abs(val - (seq)->start); @@ -77,7 +81,7 @@ void BKE_sequence_tx_set_final_left(Sequence *seq, int val) } } -void BKE_sequence_tx_set_final_right(Sequence *seq, int val) +void SEQ_transform_set_right_handle_frame(Sequence *seq, int val) { if (val > (seq)->start + (seq)->len) { seq->endstill = abs(val - (seq->start + (seq)->len)); @@ -91,15 +95,15 @@ void BKE_sequence_tx_set_final_right(Sequence *seq, int val) /* used so we can do a quick check for single image seq * since they work a bit differently to normal image seq's (during transform) */ -bool BKE_sequence_single_check(Sequence *seq) +bool SEQ_transform_single_image_check(Sequence *seq) { return ((seq->len == 1) && (seq->type == SEQ_TYPE_IMAGE || - ((seq->type & SEQ_TYPE_EFFECT) && BKE_sequence_effect_get_num_inputs(seq->type) == 0))); + ((seq->type & SEQ_TYPE_EFFECT) && SEQ_effect_get_num_inputs(seq->type) == 0))); } /* check if the selected seq's reference unselected seq's */ -bool BKE_sequence_base_isolated_sel_check(ListBase *seqbase) +bool SEQ_transform_seqbase_isolated_sel_check(ListBase *seqbase) { Sequence *seq; /* is there more than 1 select */ @@ -144,17 +148,18 @@ bool BKE_sequence_base_isolated_sel_check(ListBase *seqbase) * Use to impose limits when dragging/extending - so impossible situations don't happen. * Cant use the #SEQ_LEFTSEL and #SEQ_LEFTSEL directly because the strip may be in a meta-strip. */ -void BKE_sequence_tx_handle_xlimits(Sequence *seq, int leftflag, int rightflag) +void SEQ_transform_handle_xlimits(Sequence *seq, int leftflag, int rightflag) { if (leftflag) { - if (BKE_sequence_tx_get_final_left(seq, false) >= - BKE_sequence_tx_get_final_right(seq, false)) { - BKE_sequence_tx_set_final_left(seq, BKE_sequence_tx_get_final_right(seq, false) - 1); + if (SEQ_transform_get_left_handle_frame(seq, false) >= + SEQ_transform_get_right_handle_frame(seq, false)) { + SEQ_transform_set_left_handle_frame(seq, + SEQ_transform_get_right_handle_frame(seq, false) - 1); } - if (BKE_sequence_single_check(seq) == 0) { - if (BKE_sequence_tx_get_final_left(seq, false) >= seq_tx_get_end(seq)) { - BKE_sequence_tx_set_final_left(seq, seq_tx_get_end(seq) - 1); + if (SEQ_transform_single_image_check(seq) == 0) { + if (SEQ_transform_get_left_handle_frame(seq, false) >= seq_tx_get_end(seq)) { + SEQ_transform_set_left_handle_frame(seq, seq_tx_get_end(seq) - 1); } /* doesn't work now - TODO */ @@ -170,14 +175,15 @@ void BKE_sequence_tx_handle_xlimits(Sequence *seq, int leftflag, int rightflag) } if (rightflag) { - if (BKE_sequence_tx_get_final_right(seq, false) <= - BKE_sequence_tx_get_final_left(seq, false)) { - BKE_sequence_tx_set_final_right(seq, BKE_sequence_tx_get_final_left(seq, false) + 1); + if (SEQ_transform_get_right_handle_frame(seq, false) <= + SEQ_transform_get_left_handle_frame(seq, false)) { + SEQ_transform_set_right_handle_frame(seq, + SEQ_transform_get_left_handle_frame(seq, false) + 1); } - if (BKE_sequence_single_check(seq) == 0) { - if (BKE_sequence_tx_get_final_right(seq, false) <= seq_tx_get_start(seq)) { - BKE_sequence_tx_set_final_right(seq, seq_tx_get_start(seq) + 1); + if (SEQ_transform_single_image_check(seq) == 0) { + if (SEQ_transform_get_right_handle_frame(seq, false) <= seq_tx_get_start(seq)) { + SEQ_transform_set_right_handle_frame(seq, seq_tx_get_start(seq) + 1); } } } @@ -189,39 +195,30 @@ void BKE_sequence_tx_handle_xlimits(Sequence *seq, int leftflag, int rightflag) } } -void BKE_sequence_single_fix(Sequence *seq) +void SEQ_transform_fix_single_image_seq_offsets(Sequence *seq) { int left, start, offset; - if (!BKE_sequence_single_check(seq)) { + if (!SEQ_transform_single_image_check(seq)) { return; } /* make sure the image is always at the start since there is only one, * adjusting its start should be ok */ - left = BKE_sequence_tx_get_final_left(seq, false); + left = SEQ_transform_get_left_handle_frame(seq, false); start = seq->start; if (start != left) { offset = left - start; - BKE_sequence_tx_set_final_left(seq, BKE_sequence_tx_get_final_left(seq, false) - offset); - BKE_sequence_tx_set_final_right(seq, BKE_sequence_tx_get_final_right(seq, false) - offset); + SEQ_transform_set_left_handle_frame(seq, + SEQ_transform_get_left_handle_frame(seq, false) - offset); + SEQ_transform_set_right_handle_frame( + seq, SEQ_transform_get_right_handle_frame(seq, false) - offset); seq->start += offset; } } -bool BKE_sequence_tx_test(Sequence *seq) +bool SEQ_transform_sequence_can_be_translated(Sequence *seq) { - return !(seq->type & SEQ_TYPE_EFFECT) || (BKE_sequence_effect_get_num_inputs(seq->type) == 0); -} - -/** - * Return \a true if given \a seq needs a complete cleanup of its cache when it is transformed. - * - * Some (effect) strip types need a complete re-cache of themselves when they are transformed, - * because they do not 'contain' anything and do not have any explicit relations to other strips. - */ -bool BKE_sequence_tx_fullupdate_test(Sequence *seq) -{ - return BKE_sequence_tx_test(seq) && ELEM(seq->type, SEQ_TYPE_ADJUSTMENT, SEQ_TYPE_MULTICAM); + return !(seq->type & SEQ_TYPE_EFFECT) || (SEQ_effect_get_num_inputs(seq->type) == 0); } static bool seq_overlap(Sequence *seq1, Sequence *seq2) @@ -230,7 +227,7 @@ static bool seq_overlap(Sequence *seq1, Sequence *seq2) ((seq1->enddisp <= seq2->startdisp) || (seq1->startdisp >= seq2->enddisp)) == 0); } -bool BKE_sequence_test_overlap(ListBase *seqbasep, Sequence *test) +bool SEQ_transform_test_overlap(ListBase *seqbasep, Sequence *test) { Sequence *seq; @@ -245,43 +242,43 @@ bool BKE_sequence_test_overlap(ListBase *seqbasep, Sequence *test) return false; } -void BKE_sequence_translate(Scene *evil_scene, Sequence *seq, int delta) +void SEQ_transform_translate_sequence(Scene *evil_scene, Sequence *seq, int delta) { if (delta == 0) { return; } - BKE_sequencer_offset_animdata(evil_scene, seq, delta); + SEQ_offset_animdata(evil_scene, seq, delta); seq->start += delta; if (seq->type == SEQ_TYPE_META) { Sequence *seq_child; for (seq_child = seq->seqbase.first; seq_child; seq_child = seq_child->next) { - BKE_sequence_translate(evil_scene, seq_child, delta); + SEQ_transform_translate_sequence(evil_scene, seq_child, delta); } } - BKE_sequence_calc_disp(evil_scene, seq); + SEQ_time_update_sequence_bounds(evil_scene, seq); } /* return 0 if there weren't enough space */ -bool BKE_sequence_base_shuffle_ex(ListBase *seqbasep, - Sequence *test, - Scene *evil_scene, - int channel_delta) +bool SEQ_transform_seqbase_shuffle_ex(ListBase *seqbasep, + Sequence *test, + Scene *evil_scene, + int channel_delta) { const int orig_machine = test->machine; BLI_assert(ELEM(channel_delta, -1, 1)); test->machine += channel_delta; - BKE_sequence_calc(evil_scene, test); - while (BKE_sequence_test_overlap(seqbasep, test)) { + SEQ_time_update_sequence(evil_scene, test); + while (SEQ_transform_test_overlap(seqbasep, test)) { if ((channel_delta > 0) ? (test->machine >= MAXSEQ) : (test->machine < 1)) { break; } test->machine += channel_delta; - BKE_sequence_calc( + SEQ_time_update_sequence( evil_scene, test); // XXX - I don't think this is needed since were only moving vertically, Campbell. } @@ -301,18 +298,18 @@ bool BKE_sequence_base_shuffle_ex(ListBase *seqbasep, test->machine = orig_machine; new_frame = new_frame + (test->start - test->startdisp); /* adjust by the startdisp */ - BKE_sequence_translate(evil_scene, test, new_frame - test->start); + SEQ_transform_translate_sequence(evil_scene, test, new_frame - test->start); - BKE_sequence_calc(evil_scene, test); + SEQ_time_update_sequence(evil_scene, test); return false; } return true; } -bool BKE_sequence_base_shuffle(ListBase *seqbasep, Sequence *test, Scene *evil_scene) +bool SEQ_transform_seqbase_shuffle(ListBase *seqbasep, Sequence *test, Scene *evil_scene) { - return BKE_sequence_base_shuffle_ex(seqbasep, test, evil_scene, 1); + return SEQ_transform_seqbase_shuffle_ex(seqbasep, test, evil_scene, 1); } static int shuffle_seq_time_offset_test(ListBase *seqbasep, char dir) @@ -356,17 +353,17 @@ static int shuffle_seq_time_offset(Scene *scene, ListBase *seqbasep, char dir) for (seq = seqbasep->first; seq; seq = seq->next) { if (seq->tmp) { - BKE_sequence_calc_disp(scene, seq); /* corrects dummy startdisp/enddisp values */ + SEQ_time_update_sequence_bounds(scene, seq); /* corrects dummy startdisp/enddisp values */ } } return tot_ofs; } -bool BKE_sequence_base_shuffle_time(ListBase *seqbasep, - Scene *evil_scene, - ListBase *markers, - const bool use_sync_markers) +bool SEQ_transform_seqbase_shuffle_time(ListBase *seqbasep, + Scene *evil_scene, + ListBase *markers, + const bool use_sync_markers) { /* note: seq->tmp is used to tag strips to move */ @@ -379,7 +376,7 @@ bool BKE_sequence_base_shuffle_time(ListBase *seqbasep, if (offset) { for (seq = seqbasep->first; seq; seq = seq->next) { if (seq->tmp) { - BKE_sequence_translate(evil_scene, seq, offset); + SEQ_transform_translate_sequence(evil_scene, seq, offset); seq->flag &= ~SEQ_OVERLAP; } } @@ -397,3 +394,33 @@ bool BKE_sequence_base_shuffle_time(ListBase *seqbasep, return offset ? false : true; } + +/** + * Move strips and markers (if not locked) that start after timeline_frame by delta frames + * + * \param scene: Scene in which strips are located + * \param seqbase: ListBase in which strips are located + * \param delta: offset in frames to be applied + * \param timeline_frame: frame on timeline from where strips are moved + */ +void SEQ_transform_offset_after_frame(Scene *scene, + ListBase *seqbase, + const int delta, + const int timeline_frame) +{ + LISTBASE_FOREACH (Sequence *, seq, seqbase) { + if (seq->startdisp >= timeline_frame) { + SEQ_transform_translate_sequence(scene, seq, delta); + SEQ_time_update_sequence(scene, seq); + SEQ_relations_invalidate_cache_preprocessed(scene, seq); + } + } + + if (!scene->toolsettings->lock_markers) { + LISTBASE_FOREACH (TimeMarker *, marker, &scene->markers) { + if (marker->frame >= timeline_frame) { + marker->frame += delta; + } + } + } +} diff --git a/source/blender/sequencer/intern/utils.c b/source/blender/sequencer/intern/utils.c index 2b1d36a7709..a15465eb3c0 100644 --- a/source/blender/sequencer/intern/utils.c +++ b/source/blender/sequencer/intern/utils.c @@ -36,12 +36,17 @@ #include "BLI_listbase.h" #include "BLI_path_util.h" #include "BLI_string.h" +#include "BLI_utildefines.h" #include "BKE_image.h" #include "BKE_main.h" #include "BKE_scene.h" +#include "SEQ_iterator.h" +#include "SEQ_relations.h" +#include "SEQ_select.h" #include "SEQ_sequencer.h" +#include "SEQ_utils.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" @@ -50,11 +55,11 @@ #include "proxy.h" #include "utils.h" -void BKE_sequencer_sort(Scene *scene) +void SEQ_sort(Scene *scene) { /* all strips together per kind, and in order of y location ("machine") */ ListBase seqbase, effbase; - Editing *ed = BKE_sequencer_editing_get(scene, false); + Editing *ed = SEQ_editing_get(scene, false); Sequence *seq, *seqt; if (ed == NULL) { @@ -131,7 +136,7 @@ static int seqbase_unique_name_recursive_fn(Sequence *seq, void *arg_pt) return 1; } -void BKE_sequence_base_unique_name_recursive(ListBase *seqbasep, Sequence *seq) +void SEQ_sequence_base_unique_name_recursive(ListBase *seqbasep, Sequence *seq) { SeqUniqueInfo sui; char *dot; @@ -155,7 +160,7 @@ void BKE_sequence_base_unique_name_recursive(ListBase *seqbasep, Sequence *seq) while (sui.match) { sui.match = 0; seqbase_unique_name(seqbasep, &sui); - BKE_sequencer_base_recursive_apply(seqbasep, seqbase_unique_name_recursive_fn, &sui); + SEQ_iterator_seqbase_recursive_apply(seqbasep, seqbase_unique_name_recursive_fn, &sui); } BLI_strncpy(seq->name + 2, sui.name_dest, sizeof(seq->name) - 2); @@ -219,7 +224,7 @@ static const char *give_seqname_by_type(int type) } } -const char *BKE_sequence_give_name(Sequence *seq) +const char *SEQ_sequence_give_name(Sequence *seq) { const char *name = give_seqname_by_type(seq->type); @@ -233,7 +238,7 @@ const char *BKE_sequence_give_name(Sequence *seq) return name; } -ListBase *BKE_sequence_seqbase_get(Sequence *seq, int *r_offset) +ListBase *SEQ_get_seqbase_from_sequence(Sequence *seq, int *r_offset) { ListBase *seqbase = NULL; @@ -245,7 +250,7 @@ ListBase *BKE_sequence_seqbase_get(Sequence *seq, int *r_offset) } case SEQ_TYPE_SCENE: { if (seq->flag & SEQ_SCENE_STRIPS && seq->scene) { - Editing *ed = BKE_sequencer_editing_get(seq->scene, false); + Editing *ed = SEQ_editing_get(seq->scene, false); if (ed) { seqbase = &ed->seqbase; *r_offset = seq->scene->r.sfra; @@ -274,7 +279,7 @@ void seq_open_anim_file(Scene *scene, Sequence *seq, bool openfile) } /* reset all the previously created anims */ - BKE_sequence_free_anim(seq); + SEQ_relations_sequence_free_anim(seq); BLI_join_dirfile(name, sizeof(name), seq->strip->dir, seq->strip->stripdata->name); BLI_path_abs(name, BKE_main_blendfile_path_from_global()); @@ -387,7 +392,7 @@ void seq_open_anim_file(Scene *scene, Sequence *seq, bool openfile) } } -const Sequence *BKE_sequencer_foreground_frame_get(const Scene *scene, int frame) +const Sequence *SEQ_get_topmost_sequence(const Scene *scene, int frame) { const Editing *ed = scene->ed; const Sequence *seq, *best_seq = NULL; @@ -420,7 +425,7 @@ const Sequence *BKE_sequencer_foreground_frame_get(const Scene *scene, int frame } /* in cases where we done know the sequence's listbase */ -ListBase *BKE_sequence_seqbase(ListBase *seqbase, Sequence *seq) +ListBase *SEQ_get_seqbase_by_seq(ListBase *seqbase, Sequence *seq) { Sequence *iseq; ListBase *lb = NULL; @@ -429,7 +434,7 @@ ListBase *BKE_sequence_seqbase(ListBase *seqbase, Sequence *seq) if (seq == iseq) { return seqbase; } - if (iseq->seqbase.first && (lb = BKE_sequence_seqbase(&iseq->seqbase, seq))) { + if (iseq->seqbase.first && (lb = SEQ_get_seqbase_by_seq(&iseq->seqbase, seq))) { return lb; } } @@ -437,7 +442,7 @@ ListBase *BKE_sequence_seqbase(ListBase *seqbase, Sequence *seq) return NULL; } -Sequence *BKE_sequence_metastrip(ListBase *seqbase, Sequence *meta, Sequence *seq) +Sequence *seq_find_metastrip_by_sequence(ListBase *seqbase, Sequence *meta, Sequence *seq) { Sequence *iseq; @@ -447,7 +452,8 @@ Sequence *BKE_sequence_metastrip(ListBase *seqbase, Sequence *meta, Sequence *se if (seq == iseq) { return meta; } - if (iseq->seqbase.first && (rval = BKE_sequence_metastrip(&iseq->seqbase, iseq, seq))) { + if (iseq->seqbase.first && + (rval = seq_find_metastrip_by_sequence(&iseq->seqbase, iseq, seq))) { return rval; } } @@ -459,7 +465,7 @@ Sequence *BKE_sequence_metastrip(ListBase *seqbase, Sequence *meta, Sequence *se * Only use as last resort when the StripElem is available but no the Sequence. * (needed for RNA) */ -Sequence *BKE_sequencer_from_elem(ListBase *seqbase, StripElem *se) +Sequence *SEQ_sequence_from_strip_elem(ListBase *seqbase, StripElem *se) { Sequence *iseq; @@ -469,7 +475,7 @@ Sequence *BKE_sequencer_from_elem(ListBase *seqbase, StripElem *se) (ARRAY_HAS_ITEM(se, iseq->strip->stripdata, iseq->len))) { break; } - if ((seq_found = BKE_sequencer_from_elem(&iseq->seqbase, se))) { + if ((seq_found = SEQ_sequence_from_strip_elem(&iseq->seqbase, se))) { iseq = seq_found; break; } @@ -478,7 +484,7 @@ Sequence *BKE_sequencer_from_elem(ListBase *seqbase, StripElem *se) return iseq; } -Sequence *BKE_sequence_get_by_name(ListBase *seqbase, const char *name, bool recursive) +Sequence *SEQ_get_sequence_by_name(ListBase *seqbase, const char *name, bool recursive) { Sequence *iseq = NULL; Sequence *rseq = NULL; @@ -488,7 +494,7 @@ Sequence *BKE_sequence_get_by_name(ListBase *seqbase, const char *name, bool rec return iseq; } if (recursive && (iseq->seqbase.first) && - (rseq = BKE_sequence_get_by_name(&iseq->seqbase, name, 1))) { + (rseq = SEQ_get_sequence_by_name(&iseq->seqbase, name, 1))) { return rseq; } } @@ -496,9 +502,9 @@ Sequence *BKE_sequence_get_by_name(ListBase *seqbase, const char *name, bool rec return NULL; } -Mask *BKE_sequencer_mask_get(Scene *scene) +Mask *SEQ_active_mask_get(Scene *scene) { - Sequence *seq_act = BKE_sequencer_active_get(scene); + Sequence *seq_act = SEQ_select_active_get(scene); if (seq_act && seq_act->type == SEQ_TYPE_MASK) { return seq_act->mask; @@ -507,7 +513,7 @@ Mask *BKE_sequencer_mask_get(Scene *scene) return NULL; } -void BKE_sequence_alpha_mode_from_extension(Sequence *seq) +void SEQ_alpha_mode_from_file_extension(Sequence *seq) { if (seq->strip && seq->strip->stripdata) { const char *filename = seq->strip->stripdata->name; @@ -517,7 +523,7 @@ void BKE_sequence_alpha_mode_from_extension(Sequence *seq) /* called on draw, needs to be fast, * we could cache and use a flag if we want to make checks for file paths resolving for eg. */ -bool BKE_sequence_is_valid_check(Sequence *seq) +bool SEQ_sequence_has_source(Sequence *seq) { switch (seq->type) { case SEQ_TYPE_MASK: @@ -547,3 +553,34 @@ bool sequencer_seq_generates_image(Sequence *seq) } return false; } + +void SEQ_set_scale_to_fit(const Sequence *seq, + const int image_width, + const int image_height, + const int preview_width, + const int preview_height, + const eSeqImageFitMethod fit_method) +{ + StripTransform *transform = seq->strip->transform; + + switch (fit_method) { + case SEQ_SCALE_TO_FIT: + transform->scale_x = transform->scale_y = MIN2((float)preview_width / (float)image_width, + (float)preview_height / (float)image_height); + + break; + case SEQ_SCALE_TO_FILL: + + transform->scale_x = transform->scale_y = MAX2((float)preview_width / (float)image_width, + (float)preview_height / (float)image_height); + break; + case SEQ_STRETCH_TO_FILL: + transform->scale_x = (float)preview_width / (float)image_width; + transform->scale_y = (float)preview_height / (float)image_height; + break; + case SEQ_USE_ORIGINAL_SIZE: + transform->scale_x = 1.0f; + transform->scale_y = 1.0f; + break; + } +} diff --git a/source/blender/sequencer/intern/utils.h b/source/blender/sequencer/intern/utils.h index fe6041ec5e8..97f33bb3ae0 100644 --- a/source/blender/sequencer/intern/utils.h +++ b/source/blender/sequencer/intern/utils.h @@ -28,13 +28,12 @@ extern "C" { #endif struct Scene; -struct anim; bool sequencer_seq_generates_image(struct Sequence *seq); void seq_open_anim_file(struct Scene *scene, struct Sequence *seq, bool openfile); -struct Sequence *BKE_sequence_metastrip(ListBase *seqbase /* = ed->seqbase */, - struct Sequence *meta /* = NULL */, - struct Sequence *seq); +struct Sequence *seq_find_metastrip_by_sequence(ListBase *seqbase /* = ed->seqbase */, + struct Sequence *meta /* = NULL */, + struct Sequence *seq); #ifdef __cplusplus } diff --git a/source/blender/shader_fx/intern/FX_ui_common.c b/source/blender/shader_fx/intern/FX_ui_common.c index c1e3b2e21cd..9a86e1e96f5 100644 --- a/source/blender/shader_fx/intern/FX_ui_common.c +++ b/source/blender/shader_fx/intern/FX_ui_common.c @@ -124,6 +124,59 @@ PointerRNA *shaderfx_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ #define ERROR_LIBDATA_MESSAGE TIP_("External library data") +static void gpencil_shaderfx_ops_extra_draw(bContext *C, uiLayout *layout, void *fx_v) +{ + PointerRNA op_ptr; + uiLayout *row; + ShaderFxData *fx = (ShaderFxData *)fx_v; + + PointerRNA ptr; + Object *ob = ED_object_active_context(C); + RNA_pointer_create(&ob->id, &RNA_ShaderFx, fx, &ptr); + uiLayoutSetContextPointer(layout, "shaderfx", &ptr); + uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT); + + uiLayoutSetUnitsX(layout, 4.0f); + + /* Duplicate. */ + uiItemO(layout, + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Duplicate"), + ICON_DUPLICATE, + "OBJECT_OT_shaderfx_copy"); + + uiItemS(layout); + + /* Move to first. */ + row = uiLayoutColumn(layout, false); + uiItemFullO(row, + "OBJECT_OT_shaderfx_move_to_index", + IFACE_("Move to First"), + ICON_TRIA_UP, + NULL, + WM_OP_INVOKE_DEFAULT, + 0, + &op_ptr); + RNA_int_set(&op_ptr, "index", 0); + if (!fx->prev) { + uiLayoutSetEnabled(row, false); + } + + /* Move to last. */ + row = uiLayoutColumn(layout, false); + uiItemFullO(row, + "OBJECT_OT_shaderfx_move_to_index", + IFACE_("Move to Last"), + ICON_TRIA_DOWN, + NULL, + WM_OP_INVOKE_DEFAULT, + 0, + &op_ptr); + RNA_int_set(&op_ptr, "index", BLI_listbase_count(&ob->shader_fx) - 1); + if (!fx->next) { + uiLayoutSetEnabled(row, false); + } +} + static void shaderfx_panel_header(const bContext *UNUSED(C), Panel *panel) { uiLayout *layout = panel->layout; @@ -159,6 +212,9 @@ static void shaderfx_panel_header(const bContext *UNUSED(C), Panel *panel) uiItemR(row, ptr, "show_viewport", 0, "", ICON_NONE); uiItemR(row, ptr, "show_render", 0, "", ICON_NONE); + /* Extra operators. */ + uiItemMenuF(row, "", ICON_DOWNARROW_HLT, gpencil_shaderfx_ops_extra_draw, fx); + row = uiLayoutRow(row, false); uiLayoutSetEmboss(row, UI_EMBOSS_NONE); uiItemO(row, "", ICON_X, "OBJECT_OT_shaderfx_remove"); diff --git a/source/blender/simulation/SIM_mass_spring.h b/source/blender/simulation/SIM_mass_spring.h index 42d7c86b539..43de8b155cf 100644 --- a/source/blender/simulation/SIM_mass_spring.h +++ b/source/blender/simulation/SIM_mass_spring.h @@ -52,7 +52,7 @@ int SIM_cloth_solve(struct Depsgraph *depsgraph, struct ClothModifierData *clmd, struct ListBase *effectors); void SIM_cloth_solver_set_positions(struct ClothModifierData *clmd); -void SIM_cloth_solver_set_volume(ClothModifierData *clmd); +void SIM_cloth_solver_set_volume(struct ClothModifierData *clmd); #ifdef __cplusplus } diff --git a/source/blender/simulation/intern/hair_volume.cpp b/source/blender/simulation/intern/hair_volume.cpp index 1b65dd8f22c..08af2344bc4 100644 --- a/source/blender/simulation/intern/hair_volume.cpp +++ b/source/blender/simulation/intern/hair_volume.cpp @@ -68,13 +68,13 @@ BLI_INLINE int hair_grid_size(const int res[3]) return res[0] * res[1] * res[2]; } -typedef struct HairGridVert { +struct HairGridVert { int samples; float velocity[3]; float density; float velocity_smooth[3]; -} HairGridVert; +}; struct HairGrid { HairGridVert *verts; diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index da2115e12fb..1f205a71338 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -671,6 +671,7 @@ struct wmDrag *WM_event_start_drag( struct bContext *C, int icon, int type, void *poin, double value, unsigned int flags); void WM_event_drag_image(struct wmDrag *, struct ImBuf *, float scale, int sx, int sy); void WM_drag_free(struct wmDrag *drag); +void WM_drag_data_free(int dragtype, void *poin); void WM_drag_free_list(struct ListBase *lb); struct wmDropBox *WM_dropbox_add( @@ -681,9 +682,12 @@ struct wmDropBox *WM_dropbox_add( ListBase *WM_dropboxmap_find(const char *idname, int spaceid, int regionid); /* ID drag and drop */ -void WM_drag_add_ID(struct wmDrag *drag, struct ID *id, struct ID *from_parent); -struct ID *WM_drag_ID(const struct wmDrag *drag, short idcode); -struct ID *WM_drag_ID_from_event(const struct wmEvent *event, short idcode); +void WM_drag_add_local_ID(struct wmDrag *drag, struct ID *id, struct ID *from_parent); +struct ID *WM_drag_get_local_ID(const struct wmDrag *drag, short idcode); +struct ID *WM_drag_get_local_ID_from_event(const struct wmEvent *event, short idcode); + +struct wmDragAsset *WM_drag_get_asset_data(const struct wmDrag *drag, int idcode); +struct ID *WM_drag_get_local_ID_or_import_from_asset(const struct wmDrag *drag, int idcode); /* Set OpenGL viewport and scissor */ void wmViewport(const struct rcti *winrct); diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 7fa2851cbf3..a2cc246e21e 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -298,6 +298,8 @@ typedef struct wmNotifier { #define NC_LINESTYLE (23 << 24) #define NC_CAMERA (24 << 24) #define NC_LIGHTPROBE (25 << 24) +/* Changes to asset data in the current .blend. */ +#define NC_ASSET (26 << 24) /* data type, 256 entries is enough, it can overlap */ #define NOTE_DATA 0x00FF0000 @@ -408,20 +410,21 @@ typedef struct wmNotifier { #define ND_SPACE_IMAGE (4 << 16) #define ND_SPACE_FILE_PARAMS (5 << 16) #define ND_SPACE_FILE_LIST (6 << 16) -#define ND_SPACE_NODE (7 << 16) -#define ND_SPACE_OUTLINER (8 << 16) -#define ND_SPACE_VIEW3D (9 << 16) -#define ND_SPACE_PROPERTIES (10 << 16) -#define ND_SPACE_TEXT (11 << 16) -#define ND_SPACE_TIME (12 << 16) -#define ND_SPACE_GRAPH (13 << 16) -#define ND_SPACE_DOPESHEET (14 << 16) -#define ND_SPACE_NLA (15 << 16) -#define ND_SPACE_SEQUENCER (16 << 16) -#define ND_SPACE_NODE_VIEW (17 << 16) -#define ND_SPACE_CHANGED (18 << 16) /*sent to a new editor type after it's replaced an old one*/ -#define ND_SPACE_CLIP (19 << 16) -#define ND_SPACE_FILE_PREVIEW (20 << 16) +#define ND_SPACE_ASSET_PARAMS (7 << 16) +#define ND_SPACE_NODE (8 << 16) +#define ND_SPACE_OUTLINER (9 << 16) +#define ND_SPACE_VIEW3D (10 << 16) +#define ND_SPACE_PROPERTIES (11 << 16) +#define ND_SPACE_TEXT (12 << 16) +#define ND_SPACE_TIME (13 << 16) +#define ND_SPACE_GRAPH (14 << 16) +#define ND_SPACE_DOPESHEET (15 << 16) +#define ND_SPACE_NLA (16 << 16) +#define ND_SPACE_SEQUENCER (17 << 16) +#define ND_SPACE_NODE_VIEW (18 << 16) +#define ND_SPACE_CHANGED (19 << 16) /*sent to a new editor type after it's replaced an old one*/ +#define ND_SPACE_CLIP (20 << 16) +#define ND_SPACE_FILE_PREVIEW (21 << 16) /* subtype, 256 entries too */ #define NOTE_SUBTYPE 0x0000FF00 @@ -834,12 +837,13 @@ typedef void (*wmPaintCursorDraw)(struct bContext *C, int, int, void *customdata /* *************** Drag and drop *************** */ #define WM_DRAG_ID 0 -#define WM_DRAG_RNA 1 -#define WM_DRAG_PATH 2 -#define WM_DRAG_NAME 3 -#define WM_DRAG_VALUE 4 -#define WM_DRAG_COLOR 5 -#define WM_DRAG_DATASTACK 6 +#define WM_DRAG_ASSET 1 +#define WM_DRAG_RNA 2 +#define WM_DRAG_PATH 3 +#define WM_DRAG_NAME 4 +#define WM_DRAG_VALUE 5 +#define WM_DRAG_COLOR 6 +#define WM_DRAG_DATASTACK 7 typedef enum wmDragFlags { WM_DRAG_NOP = 0, @@ -854,6 +858,13 @@ typedef struct wmDragID { struct ID *from_parent; } wmDragID; +typedef struct wmDragAsset { + char name[64]; /* MAX_NAME */ + /* Always freed. */ + const char *path; + int id_type; +} wmDragAsset; + typedef struct wmDrag { struct wmDrag *next, *prev; diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c index 373360c7b92..fe2e2d92127 100644 --- a/source/blender/windowmanager/intern/wm_dragdrop.c +++ b/source/blender/windowmanager/intern/wm_dragdrop.c @@ -37,6 +37,7 @@ #include "BIF_glutil.h" #include "BKE_context.h" +#include "BKE_global.h" #include "BKE_idtype.h" #include "GPU_shader.h" @@ -146,16 +147,23 @@ wmDrag *WM_event_start_drag( drag->flags = flags; drag->icon = icon; drag->type = type; - if (type == WM_DRAG_PATH) { - BLI_strncpy(drag->path, poin, FILE_MAX); - } - else if (type == WM_DRAG_ID) { - if (poin) { - WM_drag_add_ID(drag, poin, NULL); - } - } - else { - drag->poin = poin; + switch (type) { + case WM_DRAG_PATH: + BLI_strncpy(drag->path, poin, FILE_MAX); + break; + case WM_DRAG_ID: + if (poin) { + WM_drag_add_local_ID(drag, poin, NULL); + } + break; + case WM_DRAG_ASSET: + /* Move ownership of poin to wmDrag. */ + drag->poin = poin; + drag->flags |= WM_DRAG_FREE_DATA; + break; + default: + drag->poin = poin; + break; } drag->value = value; @@ -170,12 +178,26 @@ void WM_event_drag_image(wmDrag *drag, ImBuf *imb, float scale, int sx, int sy) drag->sy = sy; } -void WM_drag_free(wmDrag *drag) +void WM_drag_data_free(int dragtype, void *poin) { - if ((drag->flags & WM_DRAG_FREE_DATA) && drag->poin) { - MEM_freeN(drag->poin); + /* Don't require all the callers to have a NULL-check, just allow passing NULL. */ + if (!poin) { + return; } + /* Not too nice, could become a callback. */ + if (dragtype == WM_DRAG_ASSET) { + wmDragAsset *asset_drag = poin; + MEM_freeN((void *)asset_drag->path); + } + MEM_freeN(poin); +} + +void WM_drag_free(wmDrag *drag) +{ + if (drag->flags & WM_DRAG_FREE_DATA) { + WM_drag_data_free(drag->type, drag->poin); + } BLI_freelistN(&drag->ids); MEM_freeN(drag); } @@ -279,7 +301,7 @@ void wm_drags_check_ops(bContext *C, const wmEvent *event) /* ************** IDs ***************** */ -void WM_drag_add_ID(wmDrag *drag, ID *id, ID *from_parent) +void WM_drag_add_local_ID(wmDrag *drag, ID *id, ID *from_parent) { /* Don't drag the same ID twice. */ LISTBASE_FOREACH (wmDragID *, drag_id, &drag->ids) { @@ -302,7 +324,7 @@ void WM_drag_add_ID(wmDrag *drag, ID *id, ID *from_parent) BLI_addtail(&drag->ids, drag_id); } -ID *WM_drag_ID(const wmDrag *drag, short idcode) +ID *WM_drag_get_local_ID(const wmDrag *drag, short idcode) { if (drag->type != WM_DRAG_ID) { return NULL; @@ -317,14 +339,54 @@ ID *WM_drag_ID(const wmDrag *drag, short idcode) return (idcode == 0 || GS(id->name) == idcode) ? id : NULL; } -ID *WM_drag_ID_from_event(const wmEvent *event, short idcode) +ID *WM_drag_get_local_ID_from_event(const wmEvent *event, short idcode) { if (event->custom != EVT_DATA_DRAGDROP) { return NULL; } ListBase *lb = event->customdata; - return WM_drag_ID(lb->first, idcode); + return WM_drag_get_local_ID(lb->first, idcode); +} + +wmDragAsset *WM_drag_get_asset_data(const wmDrag *drag, int idcode) +{ + if (drag->type != WM_DRAG_ASSET) { + return NULL; + } + + wmDragAsset *asset_drag = drag->poin; + return (idcode == 0 || asset_drag->id_type == idcode) ? asset_drag : NULL; +} + +static ID *wm_drag_asset_id_import(wmDragAsset *asset_drag) +{ + /* Append only for now, wmDragAsset could have a `link` bool. */ + return WM_file_append_datablock( + G_MAIN, NULL, NULL, NULL, asset_drag->path, asset_drag->id_type, asset_drag->name); +} + +/** + * When dragging a local ID, return that. Otherwise, if dragging an asset-handle, link or append + * that depending on what was chosen by the drag-box (currently append only in fact). + */ +ID *WM_drag_get_local_ID_or_import_from_asset(const wmDrag *drag, int idcode) +{ + if (!ELEM(drag->type, WM_DRAG_ASSET, WM_DRAG_ID)) { + return NULL; + } + + if (drag->type == WM_DRAG_ID) { + return WM_drag_get_local_ID(drag, idcode); + } + + wmDragAsset *asset_drag = WM_drag_get_asset_data(drag, idcode); + if (!asset_drag) { + return NULL; + } + + /* Link/append the asset. */ + return wm_drag_asset_id_import(asset_drag); } /* ************** draw ***************** */ @@ -342,7 +404,7 @@ static const char *wm_drag_name(wmDrag *drag) { switch (drag->type) { case WM_DRAG_ID: { - ID *id = WM_drag_ID(drag, 0); + ID *id = WM_drag_get_local_ID(drag, 0); bool single = (BLI_listbase_count_at_most(&drag->ids, 2) == 1); if (single) { @@ -353,6 +415,10 @@ static const char *wm_drag_name(wmDrag *drag) } break; } + case WM_DRAG_ASSET: { + const wmDragAsset *asset_drag = WM_drag_get_asset_data(drag, 0); + return asset_drag->name; + } case WM_DRAG_PATH: case WM_DRAG_NAME: return drag->path; diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index ac27862d507..82ca54db075 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -212,11 +212,11 @@ static bool wm_test_duplicate_notifier(const wmWindowManager *wm, uint type, voi LISTBASE_FOREACH (wmNotifier *, note, &wm->queue) { if ((note->category | note->data | note->subtype | note->action) == type && note->reference == reference) { - return 1; + return true; } } - return 0; + return false; } void WM_event_add_notifier_ex(wmWindowManager *wm, const wmWindow *win, uint type, void *reference) @@ -785,8 +785,8 @@ bool WM_operator_poll(bContext *C, wmOperatorType *ot) LISTBASE_FOREACH (wmOperatorTypeMacro *, macro, &ot->macro) { wmOperatorType *ot_macro = WM_operatortype_find(macro->idname, 0); - if (0 == WM_operator_poll(C, ot_macro)) { - return 0; + if (!WM_operator_poll(C, ot_macro)) { + return false; } } @@ -798,7 +798,7 @@ bool WM_operator_poll(bContext *C, wmOperatorType *ot) return ot->poll(C); } - return 1; + return true; } /* sets up the new context and calls 'wm_operator_invoke()' with poll_only */ @@ -1204,7 +1204,7 @@ static wmOperator *wm_operator_create(wmWindowManager *wm, RNA_STRUCT_END; } else { - LISTBASE_FOREACH (wmOperatorTypeMacro *, macro, &op->opm->type->macro) { + LISTBASE_FOREACH (wmOperatorTypeMacro *, macro, &ot->macro) { wmOperatorType *otm = WM_operatortype_find(macro->idname, 0); wmOperator *opm = wm_operator_create(wm, otm, macro->ptr, NULL); @@ -2293,6 +2293,11 @@ static int wm_handler_fileselect_do(bContext *C, } wm_handler_op_context(C, handler, ctx_win->eventstate); + ScrArea *handler_area = CTX_wm_area(C); + /* Make sure new context area is ready, the operator callback may operate on it. */ + if (handler_area) { + ED_area_do_refresh(C, handler_area); + } /* Needed for #UI_popup_menu_reports. */ diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 5b21b2397e7..d179cc456f4 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -2959,30 +2959,25 @@ static uiBlock *block_create_autorun_warning(struct bContext *C, void *UNUSED(arg1)) { wmWindowManager *wm = CTX_wm_manager(C); - const uiStyle *style = UI_style_get_dpi(); - const int text_points_max = MAX2(style->widget.points, style->widgetlabel.points); - const int dialog_width = text_points_max * 44 * U.dpi_fac; uiBlock *block = UI_block_begin(C, region, "autorun_warning_popup", UI_EMBOSS); - UI_block_flag_enable( block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_LOOP | UI_BLOCK_NO_WIN_CLIP | UI_BLOCK_NUMSELECT); UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP); UI_block_emboss_set(block, UI_EMBOSS); - uiLayout *layout = UI_block_layout( - block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 10, 2, dialog_width, 0, 0, style); + uiLayout *layout = uiItemsAlertBox(block, 44, ALERT_ICON_ERROR); - /* Text and some vertical space */ + /* Title and explanation text. */ uiLayout *col = uiLayoutColumn(layout, true); uiItemL_ex(col, TIP_("For security reasons, automatic execution of Python scripts " "in this file was disabled:"), - ICON_ERROR, + ICON_NONE, true, false); - uiItemL_ex(col, G.autoexec_fail, ICON_BLANK1, false, true); - uiItemL(col, TIP_("This may lead to unexpected behavior"), ICON_BLANK1); + uiItemL_ex(col, G.autoexec_fail, ICON_NONE, false, true); + uiItemL(col, TIP_("This may lead to unexpected behavior"), ICON_NONE); uiItemS(layout); @@ -2995,7 +2990,7 @@ static uiBlock *block_create_autorun_warning(struct bContext *C, TIP_("Permanently allow execution of scripts"), ICON_NONE); - uiItemS(layout); + uiItemS_ex(layout, 3.0f); /* Buttons */ uiBut *but; diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 7984c2fd879..d513598cf19 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -80,7 +80,7 @@ #include "RE_engine.h" #include "RE_pipeline.h" /* RE_ free stuff */ -#include "SEQ_sequencer.h" /* free seq clipboard */ +#include "SEQ_clipboard.h" /* free seq clipboard */ #include "IMB_thumbs.h" @@ -565,7 +565,7 @@ void WM_exit_ex(bContext *C, const bool do_python) wm_free_reports(wm); } - BKE_sequencer_free_clipboard(); /* sequencer.c */ + SEQ_clipboard_free(); /* sequencer.c */ BKE_tracking_clipboard_free(); BKE_mask_clipboard_free(); BKE_vfont_clipboard_free(); diff --git a/source/blender/windowmanager/intern/wm_jobs.c b/source/blender/windowmanager/intern/wm_jobs.c index 443a6fd1979..cf45d380c48 100644 --- a/source/blender/windowmanager/intern/wm_jobs.c +++ b/source/blender/windowmanager/intern/wm_jobs.c @@ -36,7 +36,7 @@ #include "BKE_context.h" #include "BKE_global.h" -#include "SEQ_sequencer.h" +#include "SEQ_prefetch.h" #include "WM_api.h" #include "WM_types.h" @@ -556,7 +556,7 @@ void WM_jobs_kill_all(wmWindowManager *wm) } /* This job will be automatically restarted */ - BKE_sequencer_prefetch_stop_all(); + SEQ_prefetch_stop_all(); } /* wait until every job ended, except for one owner (used in undo to keep screen job alive) */ diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c index 631a4d23eb5..8dfe26fbf79 100644 --- a/source/blender/windowmanager/intern/wm_operator_props.c +++ b/source/blender/windowmanager/intern/wm_operator_props.c @@ -198,6 +198,8 @@ void WM_operator_properties_filesel(wmOperatorType *ot, ot->srna, "filter_blenlib", (filter & FILE_TYPE_BLENDERLIB) != 0, "Filter Blender IDs", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + /* TODO asset only filter? */ + prop = RNA_def_int( ot->srna, "filemode", @@ -432,7 +434,7 @@ void WM_operator_properties_select_operation_simple(wmOperatorType *ot) void WM_operator_properties_select_walk_direction(wmOperatorType *ot) { static const EnumPropertyItem direction_items[] = { - {UI_SELECT_WALK_UP, "UP", 0, "Prev", ""}, + {UI_SELECT_WALK_UP, "UP", 0, "Previous", ""}, {UI_SELECT_WALK_DOWN, "DOWN", 0, "Next", ""}, {UI_SELECT_WALK_LEFT, "LEFT", 0, "Left", ""}, {UI_SELECT_WALK_RIGHT, "RIGHT", 0, "Right", ""}, diff --git a/source/blender/windowmanager/intern/wm_operator_type.c b/source/blender/windowmanager/intern/wm_operator_type.c index 4c4fd2b1a8e..f5cdd4490cb 100644 --- a/source/blender/windowmanager/intern/wm_operator_type.c +++ b/source/blender/windowmanager/intern/wm_operator_type.c @@ -596,7 +596,7 @@ char *WM_operatortype_description(struct bContext *C, struct wmOperatorType *ot, struct PointerRNA *properties) { - if (ot->get_description && properties) { + if (C && ot->get_description && properties) { char *description = ot->get_description(C, ot, properties); if (description) { diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 9eedd5b2faa..a5b5f082c41 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -84,6 +84,7 @@ #include "IMB_imbuf_types.h" +#include "ED_fileselect.h" #include "ED_numinput.h" #include "ED_screen.h" #include "ED_undo.h" @@ -496,7 +497,7 @@ static const char *wm_context_member_from_ptr(bContext *C, const PointerRNA *ptr } case SPACE_FILE: { const SpaceFile *sfile = (SpaceFile *)space_data; - const FileSelectParams *params = sfile->params; + const FileSelectParams *params = ED_fileselect_get_active_params(sfile); TEST_PTR_DATA_TYPE("space_data", RNA_FileSelectParams, ptr, params); break; } @@ -3997,7 +3998,7 @@ static const EnumPropertyItem *rna_id_itemf(bool *r_free, /* Show collection color tag icons in menus. */ if (id_type == ID_GR) { - item_tmp.icon = UI_icon_color_from_collection((Collection *)id); + item_tmp.icon = UI_icon_color_from_collection((struct Collection *)id); } RNA_enum_item_add(&item, &totitem, &item_tmp); diff --git a/source/blender/windowmanager/intern/wm_stereo.c b/source/blender/windowmanager/intern/wm_stereo.c index fb9c71163c8..a620accab72 100644 --- a/source/blender/windowmanager/intern/wm_stereo.c +++ b/source/blender/windowmanager/intern/wm_stereo.c @@ -188,7 +188,7 @@ void wm_stereo3d_mouse_offset_apply(wmWindow *win, int *r_mouse_xy) } if (win->stereo3d_format->display_mode == S3D_DISPLAY_SIDEBYSIDE) { - const int half_x = win->sizex / 2; + const int half_x = WM_window_pixels_x(win) / 2; /* right half of the screen */ if (r_mouse_xy[0] > half_x) { r_mouse_xy[0] -= half_x; @@ -196,7 +196,7 @@ void wm_stereo3d_mouse_offset_apply(wmWindow *win, int *r_mouse_xy) r_mouse_xy[0] *= 2; } else if (win->stereo3d_format->display_mode == S3D_DISPLAY_TOPBOTTOM) { - const int half_y = win->sizey / 2; + const int half_y = WM_window_pixels_y(win) / 2; /* upper half of the screen */ if (r_mouse_xy[1] > half_y) { r_mouse_xy[1] -= half_y; diff --git a/source/blender/windowmanager/wm.h b/source/blender/windowmanager/wm.h index baa47098bd3..c26acfc9802 100644 --- a/source/blender/windowmanager/wm.h +++ b/source/blender/windowmanager/wm.h @@ -23,7 +23,6 @@ #pragma once -struct ARegion; struct ReportList; struct wmWindow; |