diff options
Diffstat (limited to 'source/blender')
180 files changed, 4404 insertions, 2799 deletions
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 231cd0e53c5..5ad903a0119 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 0 +#define BLENDER_FILE_SUBVERSION 1 /* 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_collection.h b/source/blender/blenkernel/BKE_collection.h index f4393742dff..9a59381ab7c 100644 --- a/source/blender/blenkernel/BKE_collection.h +++ b/source/blender/blenkernel/BKE_collection.h @@ -100,6 +100,10 @@ void BKE_collection_object_move(struct Main *bmain, struct Collection *collection_dst, struct Collection *collection_src, struct Object *ob); +void BKE_collection_object_move_after(struct Main *bmain, + struct Collection *collection, + struct Object *ob_relative, + struct Object *ob); bool BKE_scene_collections_object_remove(struct Main *bmain, struct Scene *scene, diff --git a/source/blender/blenkernel/BKE_lib_override.h b/source/blender/blenkernel/BKE_lib_override.h index 5843992b25c..9a5700d2fbd 100644 --- a/source/blender/blenkernel/BKE_lib_override.h +++ b/source/blender/blenkernel/BKE_lib_override.h @@ -68,11 +68,20 @@ void BKE_lib_override_library_dependencies_tag(struct Main *bmain, struct ID *id_root, const uint tag, const bool do_create_main_relashionships); +void BKE_lib_override_library_override_group_tag(struct Main *bmain, + struct ID *id_root, + const uint tag, + const bool do_create_main_relashionships); bool BKE_lib_override_library_create(struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, struct ID *id_root, struct ID *id_reference); +bool BKE_lib_override_library_resync(struct Main *bmain, + struct Scene *scene, + struct ViewLayer *view_layer, + struct ID *id_root); +void BKE_lib_override_library_delete(struct Main *bmain, struct ID *id_root); struct IDOverrideLibraryProperty *BKE_lib_override_library_property_find( struct IDOverrideLibrary *override, const char *rna_path); diff --git a/source/blender/blenkernel/BKE_mesh_runtime.h b/source/blender/blenkernel/BKE_mesh_runtime.h index 267be4f44fd..87b55c581a2 100644 --- a/source/blender/blenkernel/BKE_mesh_runtime.h +++ b/source/blender/blenkernel/BKE_mesh_runtime.h @@ -72,9 +72,9 @@ struct Mesh *mesh_get_eval_deform(struct Depsgraph *depsgraph, const struct CustomData_MeshMasks *dataMask); struct Mesh *mesh_create_eval_final(struct Depsgraph *depsgraph, - struct Scene *scene, - struct Object *ob, - const struct CustomData_MeshMasks *dataMask); + struct Scene *scene, + struct Object *ob, + const struct CustomData_MeshMasks *dataMask); struct Mesh *mesh_create_eval_final_index_render(struct Depsgraph *depsgraph, struct Scene *scene, diff --git a/source/blender/blenkernel/BKE_nla.h b/source/blender/blenkernel/BKE_nla.h index 8b3231e5302..06e9e58d6d7 100644 --- a/source/blender/blenkernel/BKE_nla.h +++ b/source/blender/blenkernel/BKE_nla.h @@ -102,6 +102,7 @@ void BKE_nlastrip_set_active(struct AnimData *adt, struct NlaStrip *strip); bool BKE_nlastrip_within_bounds(struct NlaStrip *strip, float min, float max); void BKE_nlastrip_recalculate_bounds(struct NlaStrip *strip); +void BKE_nlastrip_recalculate_bounds_sync_action(struct NlaStrip *strip); void BKE_nlastrip_validate_name(struct AnimData *adt, struct NlaStrip *strip); diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 2029f4d38a1..d1cfa2ca9b1 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -77,6 +77,10 @@ bool BKE_object_shaderfx_use_time(struct Object *ob, struct ShaderFxData *md); bool BKE_object_support_modifier_type_check(const struct Object *ob, int modifier_type); +bool BKE_object_link_modifier(struct Object *ob_dst, + const struct Object *ob_src, + struct ModifierData *md); +bool BKE_object_link_gpencil_modifier(struct Object *ob_dst, struct GpencilModifierData *md); void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src); void BKE_object_free_modifiers(struct Object *ob, const int flag); void BKE_object_free_shaderfx(struct Object *ob, const int flag); diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index e3bd57e75e3..3ab923f05f6 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -110,6 +110,8 @@ void BKE_toolsettings_free(struct ToolSettings *toolsettings); struct Scene *BKE_scene_duplicate(struct Main *bmain, struct Scene *sce, eSceneCopyMethod type); void BKE_scene_groups_relink(struct Scene *sce); +struct Scene *BKE_scene_find_from_view_layer(const struct Main *bmain, + const struct ViewLayer *layer); struct Scene *BKE_scene_find_from_collection(const struct Main *bmain, const struct Collection *collection); diff --git a/source/blender/blenkernel/BKE_shader_fx.h b/source/blender/blenkernel/BKE_shader_fx.h index 1eb52b389d1..48d407e6db1 100644 --- a/source/blender/blenkernel/BKE_shader_fx.h +++ b/source/blender/blenkernel/BKE_shader_fx.h @@ -181,6 +181,7 @@ void BKE_shaderfx_copydata(struct ShaderFxData *fx, struct ShaderFxData *target) void BKE_shaderfx_copydata_ex(struct ShaderFxData *fx, struct ShaderFxData *target, const int flag); +void BKE_shaderfx_copy(struct ListBase *dst, const struct ListBase *src); void BKE_shaderfx_foreach_ID_link(struct Object *ob, ShaderFxIDWalkFunc walk, void *userData); bool BKE_shaderfx_has_gpencil(struct Object *ob); diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 4f587abd9f0..263f63cb6da 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -1991,9 +1991,9 @@ Mesh *mesh_get_eval_deform(struct Depsgraph *depsgraph, } Mesh *mesh_create_eval_final(Depsgraph *depsgraph, - Scene *scene, - Object *ob, - const CustomData_MeshMasks *dataMask) + Scene *scene, + Object *ob, + const CustomData_MeshMasks *dataMask) { Mesh *final; diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 5b5e32f1d81..8fe57f1bfa0 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -2192,7 +2192,15 @@ static bool animsys_evaluate_nla(NlaEvalData *echannels, if (is_inplace_tweak) { /* edit active action in-place according to its active strip, so copy the data */ memcpy(dummy_strip, adt->actstrip, sizeof(NlaStrip)); + /* Prevents nla eval from considering active strip's adj strips. + * For user, this means entering tweak mode on a strip ignores evaluating adjacent strips + * in the same track. */ dummy_strip->next = dummy_strip->prev = NULL; + + /* If tweaked strip is syncing action length, then evaluate using action length. */ + if (dummy_strip->flag & NLASTRIP_FLAG_SYNC_LENGTH) { + BKE_nlastrip_recalculate_bounds_sync_action(dummy_strip); + } } else { /* set settings of dummy NLA strip from AnimData settings */ @@ -2237,9 +2245,11 @@ static bool animsys_evaluate_nla(NlaEvalData *echannels, /* If computing the context for keyframing, store data there instead of the list. */ else { /* The extend mode here effectively controls - * whether it is possible to key-frame beyond the ends. */ - dummy_strip->extendmode = is_inplace_tweak ? NLASTRIP_EXTEND_NOTHING : - NLASTRIP_EXTEND_HOLD; + * whether it is possible to key-frame beyond the ends.*/ + dummy_strip->extendmode = (is_inplace_tweak && + !(dummy_strip->flag & NLASTRIP_FLAG_SYNC_LENGTH)) ? + NLASTRIP_EXTEND_NOTHING : + NLASTRIP_EXTEND_HOLD; r_context->eval_strip = nes = nlastrips_ctime_get_strip( NULL, &dummy_trackslist, -1, anim_eval_context, flush_to_original); diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index 0d65ee5faa3..c3c25330d3b 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -408,18 +408,28 @@ static Collection *collection_duplicate_recursive(Main *bmain, } if (do_objects) { + /* We need to first duplicate the objects in a separate loop, to support the master collection + * case, where both old and new collections are the same. + * Otherwise, depending on naming scheme and sorting, we may end up duplicating the new objects + * we just added, in some infinite loop. */ + LISTBASE_FOREACH (CollectionObject *, cob, &collection_old->gobject) { + Object *ob_old = cob->ob; + + if (ob_old->id.newid == NULL) { + BKE_object_duplicate( + bmain, ob_old, duplicate_flags, duplicate_options | LIB_ID_DUPLICATE_IS_SUBPROCESS); + } + } + /* We can loop on collection_old's objects, but have to consider it mutable because with master * collections collection_old and collection_new are the same data here. */ LISTBASE_FOREACH_MUTABLE (CollectionObject *, cob, &collection_old->gobject) { Object *ob_old = cob->ob; Object *ob_new = (Object *)ob_old->id.newid; - if (ob_new == NULL) { - ob_new = BKE_object_duplicate( - bmain, ob_old, duplicate_flags, duplicate_options | LIB_ID_DUPLICATE_IS_SUBPROCESS); - } - - if (ob_new == ob_old) { + /* New object can be NULL in master collection case, since new and old objects are in same + * collection. */ + if (ELEM(ob_new, ob_old, NULL)) { continue; } @@ -1108,6 +1118,38 @@ void BKE_collection_object_move( } } +/** + * Move object within a collection after specified object. + * + * For outliner drag & drop. + */ +void BKE_collection_object_move_after(Main *bmain, + Collection *collection, + Object *ob_relative, + Object *ob) +{ + if (ELEM(NULL, collection, ob_relative, ob)) { + return; + } + + CollectionObject *relative = BLI_findptr( + &collection->gobject, ob_relative, offsetof(CollectionObject, ob)); + if (!relative) { + return; + } + int index_to = BLI_findindex(&collection->gobject, relative); + + CollectionObject *object = BLI_findptr(&collection->gobject, ob, offsetof(CollectionObject, ob)); + if (!object) { + return; + } + int index_from = BLI_findindex(&collection->gobject, object); + + BLI_listbase_move_index(&collection->gobject, index_from, index_to); + + BKE_main_collection_sync(bmain); +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index 05c521e3b94..115980d577e 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -647,9 +647,9 @@ DO_INLINE void collision_interpolateOnTriangle(float to[3], VECADDMUL(to, v3, w3); } -static void cloth_selfcollision_impulse_vert(const float clamp_sq, - const float impulse[3], - struct ClothVertex *vert) +static void cloth_collision_impulse_vert(const float clamp_sq, + const float impulse[3], + struct ClothVertex *vert) { float impulse_len_sq = len_squared_v3(impulse); @@ -681,7 +681,7 @@ static int cloth_collision_response_static(ClothModifierData *clmd, { int result = 0; Cloth *cloth = clmd->clothObject; - const float clamp_sq = square_f(clmd->coll_parms->self_clamp * dt); + const float clamp_sq = square_f(clmd->coll_parms->clamp * dt); const float time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale); const float epsilon2 = BLI_bvhtree_get_epsilon(collmd->bvhtree); const float min_distance = (clmd->coll_parms->epsilon + epsilon2) * (8.0f / 9.0f); @@ -828,10 +828,10 @@ static int cloth_collision_response_static(ClothModifierData *clmd, } if (result) { - cloth_selfcollision_impulse_vert(clamp_sq, i1, &cloth->verts[collpair->ap1]); - cloth_selfcollision_impulse_vert(clamp_sq, i2, &cloth->verts[collpair->ap2]); + cloth_collision_impulse_vert(clamp_sq, i1, &cloth->verts[collpair->ap1]); + cloth_collision_impulse_vert(clamp_sq, i2, &cloth->verts[collpair->ap2]); if (!is_hair) { - cloth_selfcollision_impulse_vert(clamp_sq, i3, &cloth->verts[collpair->ap3]); + cloth_collision_impulse_vert(clamp_sq, i3, &cloth->verts[collpair->ap3]); } } } @@ -987,13 +987,13 @@ static int cloth_selfcollision_response_static(ClothModifierData *clmd, } if (result) { - cloth_selfcollision_impulse_vert(clamp_sq, ia[0], &cloth->verts[collpair->ap1]); - cloth_selfcollision_impulse_vert(clamp_sq, ia[1], &cloth->verts[collpair->ap2]); - cloth_selfcollision_impulse_vert(clamp_sq, ia[2], &cloth->verts[collpair->ap3]); + cloth_collision_impulse_vert(clamp_sq, ia[0], &cloth->verts[collpair->ap1]); + cloth_collision_impulse_vert(clamp_sq, ia[1], &cloth->verts[collpair->ap2]); + cloth_collision_impulse_vert(clamp_sq, ia[2], &cloth->verts[collpair->ap3]); - cloth_selfcollision_impulse_vert(clamp_sq, ib[0], &cloth->verts[collpair->bp1]); - cloth_selfcollision_impulse_vert(clamp_sq, ib[1], &cloth->verts[collpair->bp2]); - cloth_selfcollision_impulse_vert(clamp_sq, ib[2], &cloth->verts[collpair->bp3]); + cloth_collision_impulse_vert(clamp_sq, ib[0], &cloth->verts[collpair->bp1]); + cloth_collision_impulse_vert(clamp_sq, ib[1], &cloth->verts[collpair->bp2]); + cloth_collision_impulse_vert(clamp_sq, ib[2], &cloth->verts[collpair->bp3]); } } diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index 09305434289..4f65f8a57ab 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -532,6 +532,7 @@ bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[]) gpd->grid.lines = GP_DEFAULT_GRID_LINES; /* Number of lines */ /* Onion-skinning settings (data-block level) */ + gpd->onion_keytype = -1; /* All by default. */ gpd->onion_flag |= (GP_ONION_GHOST_PREVCOL | GP_ONION_GHOST_NEXTCOL); gpd->onion_flag |= GP_ONION_FADE; gpd->onion_mode = GP_ONION_MODE_RELATIVE; diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c index 5b45148ed63..cca312270bc 100644 --- a/source/blender/blenkernel/intern/lib_override.c +++ b/source/blender/blenkernel/intern/lib_override.c @@ -361,7 +361,10 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain) return success; } -static bool lib_override_hierarchy_recursive_tag(Main *bmain, ID *id, const uint tag) +static bool lib_override_hierarchy_recursive_tag(Main *bmain, + ID *id, + const uint tag, + Library *override_group_lib_reference) { void **entry_vp = BLI_ghash_lookup_p(bmain->relations->id_user_to_used, id); if (entry_vp == NULL) { @@ -369,6 +372,11 @@ static bool lib_override_hierarchy_recursive_tag(Main *bmain, ID *id, const uint return (id->tag & tag) != 0; } + if (override_group_lib_reference != NULL && ID_IS_OVERRIDE_LIBRARY_REAL(id) && + id->override_library->reference->lib == override_group_lib_reference) { + id->tag |= tag; + } + /* This way we won't process again that ID should we encounter it again through another * relationship hierarchy. * Note that this does not free any memory from relations, so we can still use the entries. @@ -383,7 +391,9 @@ static bool lib_override_hierarchy_recursive_tag(Main *bmain, ID *id, const uint } /* 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)) { + if (lib_override_hierarchy_recursive_tag( + bmain, *entry->id_pointer, tag, override_group_lib_reference) && + override_group_lib_reference == NULL) { id->tag |= tag; } } @@ -395,6 +405,7 @@ static bool lib_override_hierarchy_recursive_tag(Main *bmain, ID *id, const uint /** * Tag all IDs in given \a bmain that are being used by given \a id_root ID or its dependencies, * recursively. + * It detects and tag only chains of dependencies marked at both ends by given tag. * * This will include all local IDs, and all IDs from the same library as the \a id_root. * @@ -402,8 +413,8 @@ static bool lib_override_hierarchy_recursive_tag(Main *bmain, ID *id, const uint * \param do_create_main_relashionships Whether main relations needs to be created or already exist * (in any case, they will be freed by this function). */ -void BKE_lib_override_library_dependencies_tag(struct Main *bmain, - struct ID *id_root, +void BKE_lib_override_library_dependencies_tag(Main *bmain, + ID *id_root, const uint tag, const bool do_create_main_relashionships) { @@ -411,10 +422,36 @@ void BKE_lib_override_library_dependencies_tag(struct Main *bmain, BKE_main_relations_create(bmain, 0); } - /* Then we tag all intermediary data-blocks in-between two overridden ones (e.g. if a shapekey + /* We tag all intermediary data-blocks in-between two overridden ones (e.g. if a shapekey * has a driver using an armature object's bone, we need to override the shapekey/obdata, the * objects using them, etc.) */ - lib_override_hierarchy_recursive_tag(bmain, id_root, tag); + lib_override_hierarchy_recursive_tag(bmain, id_root, tag, NULL); + + BKE_main_relations_free(bmain); +} + +/** + * Tag all IDs in given \a bmain that are part of the same \a id_root liboverride ID group. + * That is, all other liboverrides IDs (in)directly used by \a is_root one, sharing the same + * library for their reference IDs. + * + * \param id_root The root of the hierarchy of liboverride dependencies to be tagged. + * \param do_create_main_relashionships Whether main relations needs to be created or already exist + * (in any case, they will be freed by this function). + */ +void BKE_lib_override_library_override_group_tag(Main *bmain, + ID *id_root, + const uint tag, + const bool do_create_main_relashionships) +{ + if (do_create_main_relashionships) { + BKE_main_relations_create(bmain, 0); + } + + /* 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); BKE_main_relations_free(bmain); } @@ -459,26 +496,7 @@ static int lib_override_library_make_tag_ids_cb(LibraryIDLinkCallbackData *cb_da return IDWALK_RET_NOP; } -/** - * Advanced 'smart' function to create fully functional overrides. - * - * \note Currently it only does special things if given \a id_root is an object of collection, more - * specific behaviors may be added in the future for other ID types. - * - * \note It will overrides all IDs tagged with \a LIB_TAG_DOIT, and it does not clear that tag at - * its beginning, so caller code can add extra data-blocks to be overridden as well. - * - * \note In the future that same function may be extended to support 'refresh' of overrides - * (rebuilding overrides from linked data, trying to preserve local overrides already defined). - * - * \param id_root The root ID to create an override from. - * \param id_reference some reference ID used to do some post-processing after overrides have been - * created, may be NULL. Typically, the Empty object instantiating the linked - * collection we override, currently. - * \return true if override was successfully created. - */ -bool BKE_lib_override_library_create( - Main *bmain, Scene *scene, ViewLayer *view_layer, ID *id_root, ID *id_reference) +static bool lib_override_library_create_do(Main *bmain, ID *id_root) { /* Tag all collections and objects, as well as other IDs using them. */ id_root->tag |= LIB_TAG_DOIT; @@ -508,115 +526,308 @@ bool BKE_lib_override_library_create( /* Note that this call will also free the main relations data we created above. */ BKE_lib_override_library_dependencies_tag(bmain, id_root, LIB_TAG_DOIT, false); - const bool success = BKE_lib_override_library_create_from_tag(bmain); - - if (success) { - BKE_main_collection_sync(bmain); - - switch (GS(id_root->name)) { - case ID_GR: { - Object *ob_reference = id_reference != NULL && GS(id_reference->name) == ID_OB ? - (Object *)id_reference : - NULL; - Collection *collection_new = ((Collection *)id_root->newid); - if (ob_reference != NULL) { - BKE_collection_add_from_object(bmain, scene, ob_reference, collection_new); - } - else { - BKE_collection_add_from_collection( - bmain, scene, ((Collection *)id_root), collection_new); - } + return BKE_lib_override_library_create_from_tag(bmain); +} - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection_new, ob_new) { - if (ob_new != NULL && ob_new->id.override_library != NULL) { - if (ob_reference != NULL) { - Base *base; - if ((base = BKE_view_layer_base_find(view_layer, ob_new)) == NULL) { - BKE_collection_object_add_from(bmain, scene, ob_reference, ob_new); - base = BKE_view_layer_base_find(view_layer, ob_new); - DEG_id_tag_update_ex( - bmain, &ob_new->id, ID_RECALC_TRANSFORM | ID_RECALC_BASE_FLAGS); - } +static void lib_override_library_create_post_process( + Main *bmain, Scene *scene, ViewLayer *view_layer, ID *id_root, ID *id_reference) +{ + BKE_main_collection_sync(bmain); + + switch (GS(id_root->name)) { + case ID_GR: { + Object *ob_reference = id_reference != NULL && GS(id_reference->name) == ID_OB ? + (Object *)id_reference : + NULL; + Collection *collection_new = ((Collection *)id_root->newid); + if (ob_reference != NULL) { + BKE_collection_add_from_object(bmain, scene, ob_reference, collection_new); + } + else { + BKE_collection_add_from_collection(bmain, scene, ((Collection *)id_root), collection_new); + } - if (ob_new == (Object *)ob_reference->id.newid) { - /* TODO: is setting active needed? */ - BKE_view_layer_base_select_and_set_active(view_layer, base); - } - } - else if (BKE_view_layer_base_find(view_layer, ob_new) == NULL) { - BKE_collection_object_add(bmain, collection_new, ob_new); + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection_new, ob_new) { + if (ob_new != NULL && ob_new->id.override_library != NULL) { + if (ob_reference != NULL) { + Base *base; + if ((base = BKE_view_layer_base_find(view_layer, ob_new)) == NULL) { + BKE_collection_object_add_from(bmain, scene, ob_reference, ob_new); + base = BKE_view_layer_base_find(view_layer, ob_new); DEG_id_tag_update_ex(bmain, &ob_new->id, ID_RECALC_TRANSFORM | ID_RECALC_BASE_FLAGS); } + + if (ob_new == (Object *)ob_reference->id.newid) { + /* TODO: is setting active needed? */ + BKE_view_layer_base_select_and_set_active(view_layer, base); + } + } + else if (BKE_view_layer_base_find(view_layer, ob_new) == NULL) { + BKE_collection_object_add(bmain, collection_new, ob_new); + DEG_id_tag_update_ex(bmain, &ob_new->id, ID_RECALC_TRANSFORM | ID_RECALC_BASE_FLAGS); } } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; - break; } - case ID_OB: { - BKE_collection_object_add_from( - bmain, scene, (Object *)id_root, ((Object *)id_root->newid)); - break; - } - default: - break; + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + break; } + case ID_OB: { + BKE_collection_object_add_from(bmain, scene, (Object *)id_root, ((Object *)id_root->newid)); + break; + } + default: + break; + } - /* We need to ensure all new overrides of objects are properly instantiated. */ - LISTBASE_FOREACH (Object *, ob, &bmain->objects) { - Object *ob_new = (Object *)ob->id.newid; - if (ob_new != NULL) { - BLI_assert(ob_new->id.override_library != NULL && - ob_new->id.override_library->reference == &ob->id); - - Collection *default_instantiating_collection = NULL; - if (BKE_view_layer_base_find(view_layer, ob_new) == NULL) { - if (default_instantiating_collection == NULL) { - switch (GS(id_root->name)) { - case ID_GR: { - default_instantiating_collection = BKE_collection_add( - bmain, (Collection *)id_root, "OVERRIDE_HIDDEN"); - break; - } - case ID_OB: { - /* Add the new container collection to one of the collections instantiating the - * root object, or scene's master collection if none found. */ - Object *ob_root = (Object *)id_root; - LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { - if (BKE_collection_has_object(collection, ob_root) && - BKE_view_layer_has_collection(view_layer, collection) && - !ID_IS_LINKED(collection) && !ID_IS_OVERRIDE_LIBRARY(collection)) { - default_instantiating_collection = BKE_collection_add( - bmain, collection, "OVERRIDE_HIDDEN"); - } - } - if (default_instantiating_collection == NULL) { + /* We need to ensure all new overrides of objects are properly instantiated. */ + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + Object *ob_new = (Object *)ob->id.newid; + if (ob_new != NULL) { + BLI_assert(ob_new->id.override_library != NULL && + ob_new->id.override_library->reference == &ob->id); + + Collection *default_instantiating_collection = NULL; + if (BKE_view_layer_base_find(view_layer, ob_new) == NULL) { + if (default_instantiating_collection == NULL) { + switch (GS(id_root->name)) { + case ID_GR: { + default_instantiating_collection = BKE_collection_add( + bmain, (Collection *)id_root, "OVERRIDE_HIDDEN"); + break; + } + case ID_OB: { + /* Add the new container collection to one of the collections instantiating the + * root object, or scene's master collection if none found. */ + Object *ob_root = (Object *)id_root; + LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { + if (BKE_collection_has_object(collection, ob_root) && + BKE_view_layer_has_collection(view_layer, collection) && + !ID_IS_LINKED(collection) && !ID_IS_OVERRIDE_LIBRARY(collection)) { default_instantiating_collection = BKE_collection_add( - bmain, scene->master_collection, "OVERRIDE_HIDDEN"); + bmain, collection, "OVERRIDE_HIDDEN"); } - break; } - default: - BLI_assert(0); + if (default_instantiating_collection == NULL) { + default_instantiating_collection = BKE_collection_add( + bmain, scene->master_collection, "OVERRIDE_HIDDEN"); + } + break; } - /* Hide the collection from viewport and render. */ - default_instantiating_collection->flag |= COLLECTION_RESTRICT_VIEWPORT | - COLLECTION_RESTRICT_RENDER; + default: + BLI_assert(0); + } + /* Hide the collection from viewport and render. */ + default_instantiating_collection->flag |= COLLECTION_RESTRICT_VIEWPORT | + COLLECTION_RESTRICT_RENDER; + } + + BKE_collection_object_add(bmain, default_instantiating_collection, ob_new); + DEG_id_tag_update_ex(bmain, &ob_new->id, ID_RECALC_TRANSFORM | ID_RECALC_BASE_FLAGS); + } + } + } +} + +/** + * Advanced 'smart' function to create fully functional overrides. + * + * \note Currently it only does special things if given \a id_root is an object of collection, more + * specific behaviors may be added in the future for other ID types. + * + * \note It will overrides all IDs tagged with \a LIB_TAG_DOIT, and it does not clear that tag at + * its beginning, so caller code can add extra data-blocks to be overridden as well. + * + * \note In the future that same function may be extended to support 'refresh' of overrides + * (rebuilding overrides from linked data, trying to preserve local overrides already defined). + * + * \param id_root The root ID to create an override from. + * \param id_reference some reference ID used to do some post-processing after overrides have been + * created, may be NULL. Typically, the Empty object instantiating the linked + * collection we override, currently. + * \return true if override was successfully created. + */ +bool BKE_lib_override_library_create( + Main *bmain, Scene *scene, ViewLayer *view_layer, ID *id_root, ID *id_reference) +{ + const bool success = lib_override_library_create_do(bmain, id_root); + + if (!success) { + return success; + } + + lib_override_library_create_post_process(bmain, scene, view_layer, id_root, id_reference); + + /* Cleanup. */ + BKE_main_id_clear_newpoins(bmain); + BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); + + return success; +} + +/** + * Advanced 'smart' function to resync, re-create fully functional overrides up-to-date with linked + * data, from an existing override hierarchy. + * + * \param id_root The root liboverride ID to resync from. + * \return true if override was successfully resynced. + */ +bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_layer, ID *id_root) +{ + BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root)); + + /* Tag all collections and objects, as well as other IDs using them. */ + id_root->tag |= LIB_TAG_DOIT; + ID *id_root_reference = id_root->override_library->reference; + + /* 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); + + GHash *linkedref_to_old_override = BLI_ghash_new( + BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__); + ID *id; + FOREACH_MAIN_ID_BEGIN (bmain, id) { + if (id->tag & LIB_TAG_DOIT && ID_IS_OVERRIDE_LIBRARY_REAL(id)) { + /* While this should not happen in typical cases (and won't be properly supported here), user + * is free to do all kind of very bad things, including having different local overrides of a + * same linked ID in a same hierarchy... */ + if (!BLI_ghash_haskey(linkedref_to_old_override, id->override_library->reference)) { + BLI_ghash_insert(linkedref_to_old_override, id->override_library->reference, id); + id->override_library->reference->tag |= LIB_TAG_DOIT; + } + } + } + FOREACH_MAIN_ID_END; + + /* Make new override from linked data. */ + /* Note that this call also remap all pointers of tagged IDs from old override IDs to new + * override IDs (including within the old overrides themselves, since those are tagged too + * above). */ + const bool success = lib_override_library_create_do(bmain, id_root_reference); + + if (!success) { + return success; + } + + ListBase *lb; + FOREACH_MAIN_LISTBASE_BEGIN (bmain, lb) { + FOREACH_MAIN_LISTBASE_ID_BEGIN (lb, id) { + if (id->tag & LIB_TAG_DOIT && id->newid != NULL && ID_IS_LINKED(id)) { + ID *id_override_new = id->newid; + ID *id_override_old = BLI_ghash_lookup(linkedref_to_old_override, id); + + if (id_override_old != NULL) { + /* Swap the names between old override ID and new one. */ + char id_name_buf[MAX_ID_NAME]; + memcpy(id_name_buf, id_override_old->name, sizeof(id_name_buf)); + memcpy(id_override_old->name, id_override_new->name, sizeof(id_override_old->name)); + memcpy(id_override_new->name, id_name_buf, sizeof(id_override_new->name)); + /* Note that this is very efficient way to keep BMain IDs ordered as expected after + * swapping their names. + * However, one has to be very careful with this when iterating over the listbase at the + * same time. Here it works because we only execute this code when we are in the linked + * IDs, which are always *after* all local ones, and we only affect local IDs. */ + BLI_listbase_swaplinks(lb, id_override_old, id_override_new); + + /* Remap the whole local IDs to use the new override. */ + BKE_libblock_remap( + bmain, id_override_old, id_override_new, ID_REMAP_SKIP_INDIRECT_USAGE); + + /* Copy over overrides rules from old override ID to new one. */ + BLI_duplicatelist(&id_override_new->override_library->properties, + &id_override_old->override_library->properties); + for (IDOverrideLibraryProperty * + op_new = id_override_new->override_library->properties.first, + *op_old = id_override_old->override_library->properties.first; + op_new; + op_new = op_new->next, op_old = op_old->next) { + lib_override_library_property_copy(op_new, op_old); } - BKE_collection_object_add(bmain, default_instantiating_collection, ob_new); - DEG_id_tag_update_ex(bmain, &ob_new->id, ID_RECALC_TRANSFORM | ID_RECALC_BASE_FLAGS); + /* Apply rules on new override ID using old one as 'source' data. */ + /* Note that since we already remapped ID pointers in old override IDs to new ones, we + * can also apply ID pointer override rules safely here. */ + PointerRNA rnaptr_src, rnaptr_dst; + RNA_id_pointer_create(id_override_old, &rnaptr_src); + RNA_id_pointer_create(id_override_new, &rnaptr_dst); + + RNA_struct_override_apply( + bmain, &rnaptr_dst, &rnaptr_src, NULL, id_override_new->override_library); } } } + FOREACH_MAIN_LISTBASE_ID_END; + } + FOREACH_MAIN_LISTBASE_END; + + /* Delete old override IDs. */ + FOREACH_MAIN_ID_BEGIN (bmain, id) { + if (id->tag & LIB_TAG_DOIT && id->newid != NULL && ID_IS_LINKED(id)) { + ID *id_override_old = BLI_ghash_lookup(linkedref_to_old_override, id); + + if (id_override_old != NULL) { + BKE_id_delete(bmain, id_override_old); + } + } } + FOREACH_MAIN_ID_END; + + /* Essentially ensures that potentially new overrides of new objects will be instantiated. */ + lib_override_library_create_post_process(bmain, scene, view_layer, id_root_reference, id_root); /* Cleanup. */ + BLI_ghash_free(linkedref_to_old_override, NULL, NULL); + BKE_main_id_clear_newpoins(bmain); BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); return success; } +/** + * Advanced 'smart' function to delete library overrides (including their existing override + * hierarchy) and remap their usages to their linked reference IDs. + * + * \note All IDs tagged with `LIB_TAG_DOIT` will be deleted. + * + * \param id_root The root liboverride ID to resync from. + */ +void BKE_lib_override_library_delete(Main *bmain, ID *id_root) +{ + BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root)); + + /* Tag all collections and objects, as well as other IDs using them. */ + id_root->tag |= LIB_TAG_DOIT; + + /* 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); + + ID *id; + FOREACH_MAIN_ID_BEGIN (bmain, id) { + if (id->tag & LIB_TAG_DOIT) { + if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) { + ID *id_override_reference = id->override_library->reference; + + /* Remap the whole local IDs to use the linked data. */ + BKE_libblock_remap(bmain, id, id_override_reference, ID_REMAP_SKIP_INDIRECT_USAGE); + } + } + } + FOREACH_MAIN_ID_END; + + /* Delete the override IDs. */ + FOREACH_MAIN_ID_BEGIN (bmain, id) { + if (id->tag & LIB_TAG_DOIT) { + BKE_id_delete(bmain, id); + } + } + FOREACH_MAIN_ID_END; + + /* Should not actually be needed here... */ + BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); +} + BLI_INLINE IDOverrideLibraryRuntime *override_library_rna_path_runtime_ensure( IDOverrideLibrary *override) { diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index de07c96e3f0..d2f7ee68430 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -196,11 +196,11 @@ MetaElem *BKE_mball_element_add(MetaBall *mb, const int type) return ml; } /** - * Compute bounding box of all MetaElems/MetaBalls. + * Compute bounding box of all #MetaElem / #MetaBall * - * Bounding box is computed from polygonized surface. Object *ob is - * basic MetaBall (usually with name Meta). All other MetaBalls (with - * names Meta.001, Meta.002, etc) are included in this Bounding Box. + * Bounding box is computed from polygonized surface. \a ob is + * basic meta-balls (with name `Meta` for example). All other meta-ball objects + * (with names `Meta.001`, `Meta.002`, etc) are included in this bounding-box. */ void BKE_mball_texspace_calc(Object *ob) { @@ -298,25 +298,30 @@ float *BKE_mball_make_orco(Object *ob, ListBase *dispbase) return orcodata; } -/* Note on mball basis stuff 2.5x (this is a can of worms) +/** + * \brief Test, if \a ob is a basis meta-ball. + * + * It test last character of Object ID name. If last character + * is digit it return 0, else it return 1. + * + * + * Meta-Ball Basis Notes from Blender-2.5x + * ======================================= + * + * This is a can of worms. + * * This really needs a rewrite/refactor its totally broken in anything other then basic cases - * Multiple Scenes + Set Scenes & mixing mball basis SHOULD work but fails to update the depsgraph - * on rename and linking into scenes or removal of basis mball. + * Multiple Scenes + Set Scenes & mixing meta-ball basis _should_ work but fails to update the + * depsgraph on rename and linking into scenes or removal of basis meta-ball. * So take care when changing this code. * - * Main idiot thing here is that the system returns find_basis_mball() - * objects which fail a is_basis_mball() test. + * Main idiot thing here is that the system returns #BKE_mball_basis_find() + * objects which fail a #BKE_mball_is_basis() test. * - * Not only that but the depsgraph and their areas depend on this behavior!, + * Not only that but the depsgraph and their areas depend on this behavior, * so making small fixes here isn't worth it. * - Campbell */ - -/** \brief Test, if Object *ob is basic MetaBall. - * - * It test last character of Object ID name. If last character - * is digit it return 0, else it return 1. - */ bool BKE_mball_is_basis(Object *ob) { /* just a quick test */ @@ -378,12 +383,12 @@ bool BKE_mball_is_any_unselected(const MetaBall *mb) } /** - * \brief copy some properties from object to other metaball object with same base name + * \brief copy some properties from object to other meta-ball object with same base name * - * When some properties (wiresize, threshold, update flags) of metaball are changed, then this - * properties are copied to all metaballs in same "group" (metaballs with same base name: MBall, - * MBall.001, MBall.002, etc). The most important is to copy properties to the base metaball, - * because this metaball influence polygonization of metaballs. */ + * When some properties (wire-size, threshold, update flags) of meta-ball are changed, then this + * properties are copied to all meta-balls in same "group" (meta-balls with same base name: + * `MBall`, `MBall.001`, `MBall.002`, etc). The most important is to copy properties to the base + * meta-ball, because this meta-ball influence polygonization of meta-balls. */ void BKE_mball_properties_copy(Scene *scene, Object *active_object) { Scene *sce_iter = scene; @@ -397,7 +402,7 @@ void BKE_mball_properties_copy(Scene *scene, Object *active_object) BLI_split_name_num(basisname, &basisnr, active_object->id.name + 2, '.'); /* Pass depsgraph as NULL, which means we will not expand into - * duplis unlike when we generate the mball. Expanding duplis + * duplis unlike when we generate the meta-ball. Expanding duplis * would not be compatible when editing multiple view layers. */ BKE_scene_base_iter_next(NULL, &iter, &sce_iter, 0, NULL, NULL); while (BKE_scene_base_iter_next(NULL, &iter, &sce_iter, 1, &base, &ob)) { @@ -424,12 +429,11 @@ void BKE_mball_properties_copy(Scene *scene, Object *active_object) /** \brief This function finds basic MetaBall. * - * Basic MetaBall doesn't include any number at the end of - * its name. All MetaBalls with same base of name can be - * blended. MetaBalls with different basic name can't be - * blended. + * Basic meta-ball doesn't include any number at the end of + * its name. All meta-balls with same base of name can be + * blended. meta-balls with different basic name can't be blended. * - * warning!, is_basis_mball() can fail on returned object, see long note above. + * \warning #BKE_mball_is_basis() can fail on returned object, see function docs for details. */ Object *BKE_mball_basis_find(Scene *scene, Object *basis) { diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index 1ba82b352d1..e5527ed987a 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -1361,6 +1361,25 @@ static void nlastrip_fix_resize_overlaps(NlaStrip *strip) } } +/** Recalculate the start and end frames for the strip to match the bounds of its action such that + * the overall NLA animation result is unchanged. */ +void BKE_nlastrip_recalculate_bounds_sync_action(NlaStrip *strip) +{ + float prev_actstart; + + if (strip == NULL || strip->type != NLASTRIP_TYPE_CLIP) { + return; + } + + prev_actstart = strip->actstart; + + calc_action_range(strip->act, &strip->actstart, &strip->actend, 0); + + /* Set start such that key's do not visually move, to preserve the overall animation result. */ + strip->start += (strip->actstart - prev_actstart) * strip->scale; + + BKE_nlastrip_recalculate_bounds(strip); +} /* Recalculate the start and end frames for the current strip, after changing * the extents of the action or the mapping (repeats or scale factor) info */ @@ -2133,11 +2152,7 @@ void BKE_nla_tweakmode_exit(AnimData *adt) /* must be action-clip only (transitions don't have scale) */ if ((strip->type == NLASTRIP_TYPE_CLIP) && (strip->act)) { - /* recalculate the length of the action */ - calc_action_range(strip->act, &strip->actstart, &strip->actend, 0); - - /* adjust the strip extents in response to this */ - BKE_nlastrip_recalculate_bounds(strip); + BKE_nlastrip_recalculate_bounds_sync_action(strip); } } @@ -2151,11 +2166,7 @@ void BKE_nla_tweakmode_exit(AnimData *adt) /* sync strip extents if this strip uses the same action */ if ((adt->actstrip) && (adt->actstrip->act == strip->act) && (strip->flag & NLASTRIP_FLAG_SYNC_LENGTH)) { - /* recalculate the length of the action */ - calc_action_range(strip->act, &strip->actstart, &strip->actend, 0); - - /* adjust the strip extents in response to this */ - BKE_nlastrip_recalculate_bounds(strip); + BKE_nlastrip_recalculate_bounds_sync_action(strip); } /* clear tweakuser flag */ diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 31420b3adc6..a7aeee1644b 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -689,6 +689,60 @@ bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type) return false; } +bool BKE_object_link_modifier(struct Object *ob_dst, const struct Object *ob_src, ModifierData *md) +{ + ModifierData *nmd = NULL; + + if (ELEM(md->type, eModifierType_Hook, eModifierType_Collision)) { + return false; + } + + if (!BKE_object_support_modifier_type_check(ob_dst, md->type)) { + return false; + } + + switch (md->type) { + case eModifierType_Softbody: + BKE_object_copy_softbody(ob_dst, ob_src, 0); + break; + case eModifierType_Skin: + /* ensure skin-node customdata exists */ + BKE_mesh_ensure_skin_customdata(ob_dst->data); + break; + } + + nmd = BKE_modifier_new(md->type); + BLI_strncpy(nmd->name, md->name, sizeof(nmd->name)); + + if (md->type == eModifierType_Multires) { + /* Has to be done after mod creation, but *before* we actually copy its settings! */ + multiresModifier_sync_levels_ex( + ob_dst, (MultiresModifierData *)md, (MultiresModifierData *)nmd); + } + + BKE_modifier_copydata(md, nmd); + BLI_addtail(&ob_dst->modifiers, nmd); + BKE_modifier_unique_name(&ob_dst->modifiers, nmd); + + return true; +} + +bool BKE_object_link_gpencil_modifier(struct Object *ob_dst, GpencilModifierData *md) +{ + GpencilModifierData *nmd = NULL; + + nmd = BKE_gpencil_modifier_new(md->type); + BLI_strncpy(nmd->name, md->name, sizeof(nmd->name)); + + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type); + mti->copyData(md, nmd); + + BLI_addtail(&ob_dst->greasepencil_modifiers, nmd); + BKE_gpencil_modifier_unique_name(&ob_dst->greasepencil_modifiers, nmd); + + return true; +} + void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src) { BKE_object_free_modifiers(ob_dst, 0); @@ -702,54 +756,14 @@ void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_sr /* No grease pencil modifiers. */ if ((ob_src->type != OB_GPENCIL) && (ob_dst->type != OB_GPENCIL)) { LISTBASE_FOREACH (ModifierData *, md, &ob_src->modifiers) { - ModifierData *nmd = NULL; - - if (ELEM(md->type, eModifierType_Hook, eModifierType_Collision)) { - continue; - } - - if (!BKE_object_support_modifier_type_check(ob_dst, md->type)) { - continue; - } - - switch (md->type) { - case eModifierType_Softbody: - BKE_object_copy_softbody(ob_dst, ob_src, 0); - break; - case eModifierType_Skin: - /* ensure skin-node customdata exists */ - BKE_mesh_ensure_skin_customdata(ob_dst->data); - break; - } - - nmd = BKE_modifier_new(md->type); - BLI_strncpy(nmd->name, md->name, sizeof(nmd->name)); - - if (md->type == eModifierType_Multires) { - /* Has to be done after mod creation, but *before* we actually copy its settings! */ - multiresModifier_sync_levels_ex( - ob_dst, (MultiresModifierData *)md, (MultiresModifierData *)nmd); - } - - BKE_modifier_copydata(md, nmd); - BLI_addtail(&ob_dst->modifiers, nmd); - BKE_modifier_unique_name(&ob_dst->modifiers, nmd); + BKE_object_link_modifier(ob_dst, ob_src, md); } } /* Copy grease pencil modifiers. */ if ((ob_src->type == OB_GPENCIL) && (ob_dst->type == OB_GPENCIL)) { LISTBASE_FOREACH (GpencilModifierData *, md, &ob_src->greasepencil_modifiers) { - GpencilModifierData *nmd = NULL; - - nmd = BKE_gpencil_modifier_new(md->type); - BLI_strncpy(nmd->name, md->name, sizeof(nmd->name)); - - const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type); - mti->copyData(md, nmd); - - BLI_addtail(&ob_dst->greasepencil_modifiers, nmd); - BKE_gpencil_modifier_unique_name(&ob_dst->greasepencil_modifiers, nmd); + BKE_object_link_gpencil_modifier(ob_dst, md); } } diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 6f1cca619ff..1dc51c9ddae 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -1129,6 +1129,17 @@ int BKE_scene_base_iter_next( return iter->phase; } +Scene *BKE_scene_find_from_view_layer(const Main *bmain, const ViewLayer *layer) +{ + for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { + if (BLI_findindex(&scene->view_layers, layer) != -1) { + return scene; + } + } + + return NULL; +} + Scene *BKE_scene_find_from_collection(const Main *bmain, const Collection *collection) { for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { @@ -2246,6 +2257,7 @@ static Depsgraph **scene_get_depsgraph_p(Main *bmain, { BLI_assert(scene != NULL); BLI_assert(view_layer != NULL); + BLI_assert(BKE_scene_find_from_view_layer(bmain, view_layer) == scene); /* Make sure hash itself exists. */ if (allocate_ghash_entry) { BKE_scene_ensure_depsgraph_hash(scene); diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c index c6daecbcee6..aba9b255f40 100644 --- a/source/blender/blenkernel/intern/seqeffects.c +++ b/source/blender/blenkernel/intern/seqeffects.c @@ -2437,16 +2437,16 @@ static void transform_image(int x, } static void do_transform_effect(const SeqRenderData *context, - Sequence *seq, - float UNUSED(cfra), - float UNUSED(facf0), - float UNUSED(facf1), - ImBuf *ibuf1, - ImBuf *UNUSED(ibuf2), - ImBuf *UNUSED(ibuf3), - int start_line, - int total_lines, - ImBuf *out) + Sequence *seq, + float UNUSED(cfra), + float UNUSED(facf0), + float UNUSED(facf1), + ImBuf *ibuf1, + ImBuf *UNUSED(ibuf2), + ImBuf *UNUSED(ibuf3), + int start_line, + int total_lines, + ImBuf *out) { Scene *scene = context->scene; TransformVars *transform = (TransformVars *)seq->effectdata; diff --git a/source/blender/blenkernel/intern/shader_fx.c b/source/blender/blenkernel/intern/shader_fx.c index b3d350f5ccd..4ad67a1dd32 100644 --- a/source/blender/blenkernel/intern/shader_fx.c +++ b/source/blender/blenkernel/intern/shader_fx.c @@ -234,6 +234,19 @@ void BKE_shaderfx_copydata(ShaderFxData *fx, ShaderFxData *target) BKE_shaderfx_copydata_ex(fx, target, 0); } +void BKE_shaderfx_copy(ListBase *dst, const ListBase *src) +{ + ShaderFxData *fx; + ShaderFxData *srcfx; + + BLI_listbase_clear(dst); + BLI_duplicatelist(dst, src); + + for (srcfx = src->first, fx = dst->first; srcfx && fx; srcfx = srcfx->next, fx = fx->next) { + BKE_shaderfx_copydata(srcfx, fx); + } +} + ShaderFxData *BKE_shaderfx_findby_type(Object *ob, ShaderFxType type) { ShaderFxData *fx = ob->shader_fx.first; diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c index 8414f93ddaa..9b78c9e5fc3 100644 --- a/source/blender/blenkernel/intern/unit.c +++ b/source/blender/blenkernel/intern/unit.c @@ -757,7 +757,6 @@ static char *find_next_op(const char *str, char *remaining_str, int len_max) if (ch_is_op(remaining_str[i])) { if (scientific_notation) { scientific_notation = false; - continue; } /* Make sure we don't look backwards before the start of the string. */ diff --git a/source/blender/blenlib/BLI_array.hh b/source/blender/blenlib/BLI_array.hh index 9d09bb3559e..0ffe6b9a750 100644 --- a/source/blender/blenlib/BLI_array.hh +++ b/source/blender/blenlib/BLI_array.hh @@ -77,32 +77,39 @@ class Array { /** * By default an empty array is created. */ - Array() + Array(Allocator allocator = {}) noexcept : allocator_(allocator) { data_ = inline_buffer_; size_ = 0; } + Array(NoExceptConstructor, Allocator allocator = {}) noexcept : Array(allocator) + { + } + /** * Create a new array that contains copies of all values. */ template<typename U, typename std::enable_if_t<std::is_convertible_v<U, T>> * = nullptr> - Array(Span<U> values, Allocator allocator = {}) : allocator_(allocator) + Array(Span<U> values, Allocator allocator = {}) : Array(NoExceptConstructor(), allocator) { - size_ = values.size(); - data_ = this->get_buffer_for_size(values.size()); - uninitialized_convert_n<U, T>(values.data(), size_, data_); + const int64_t size = values.size(); + data_ = this->get_buffer_for_size(size); + uninitialized_convert_n<U, T>(values.data(), size, data_); + size_ = size; } /** * Create a new array that contains copies of all values. */ template<typename U, typename std::enable_if_t<std::is_convertible_v<U, T>> * = nullptr> - Array(const std::initializer_list<U> &values) : Array(Span<U>(values)) + Array(const std::initializer_list<U> &values, Allocator allocator = {}) + : Array(Span<U>(values), allocator) { } - Array(const std::initializer_list<T> &values) : Array(Span<T>(values)) + Array(const std::initializer_list<T> &values, Allocator allocator = {}) + : Array(Span<T>(values), allocator) { } @@ -114,23 +121,24 @@ class Array { * even for non-trivial types. This should not be the default though, because one can easily mess * up when dealing with uninitialized memory. */ - explicit Array(int64_t size) + explicit Array(int64_t size, Allocator allocator = {}) : Array(NoExceptConstructor(), allocator) { - size_ = size; data_ = this->get_buffer_for_size(size); default_construct_n(data_, size); + size_ = size; } /** * Create a new array with the given size. All values will be initialized by copying the given * default. */ - Array(int64_t size, const T &value) + Array(int64_t size, const T &value, Allocator allocator = {}) + : Array(NoExceptConstructor(), allocator) { BLI_assert(size >= 0); - size_ = size; data_ = this->get_buffer_for_size(size); - uninitialized_fill_n(data_, size_, value); + uninitialized_fill_n(data_, size, value); + size_ = size; } /** @@ -145,28 +153,28 @@ class Array { * Usage: * Array<std::string> my_strings(10, NoInitialization()); */ - Array(int64_t size, NoInitialization) + Array(int64_t size, NoInitialization, Allocator allocator = {}) + : Array(NoExceptConstructor(), allocator) { BLI_assert(size >= 0); - size_ = size; data_ = this->get_buffer_for_size(size); + size_ = size; } Array(const Array &other) : Array(other.as_span(), other.allocator_) { } - Array(Array &&other) noexcept : allocator_(other.allocator_) + Array(Array &&other) noexcept(std::is_nothrow_move_constructible_v<T>) + : Array(NoExceptConstructor(), other.allocator_) { - size_ = other.size_; - - if (!other.uses_inline_buffer()) { - data_ = other.data_; + if (other.uses_inline_buffer()) { + uninitialized_relocate_n(other.data_, other.size_, data_); } else { - data_ = this->get_buffer_for_size(size_); - uninitialized_relocate_n(other.data_, size_, data_); + data_ = other.data_; } + size_ = other.size_; other.data_ = other.inline_buffer_; other.size_ = 0; @@ -182,24 +190,12 @@ class Array { Array &operator=(const Array &other) { - if (this == &other) { - return *this; - } - - this->~Array(); - new (this) Array(other); - return *this; + return copy_assign_container(*this, other); } - Array &operator=(Array &&other) + Array &operator=(Array &&other) noexcept(std::is_nothrow_move_constructible_v<T>) { - if (this == &other) { - return *this; - } - - this->~Array(); - new (this) Array(std::move(other)); - return *this; + return move_assign_container(*this, std::move(other)); } T &operator[](int64_t index) diff --git a/source/blender/blenlib/BLI_memory_utils.hh b/source/blender/blenlib/BLI_memory_utils.hh index 7216536a884..49076bb1aae 100644 --- a/source/blender/blenlib/BLI_memory_utils.hh +++ b/source/blender/blenlib/BLI_memory_utils.hh @@ -162,7 +162,7 @@ void uninitialized_convert_n(const From *src, int64_t n, To *dst) int64_t current = 0; try { for (; current < n; current++) { - new (static_cast<void *>(dst + current)) To((To)src[current]); + new (static_cast<void *>(dst + current)) To(static_cast<To>(src[current])); } } catch (...) { @@ -410,6 +410,15 @@ class NoInitialization { }; /** + * This can be used to mark a constructor of an object that does not throw exceptions. Other + * constructors can delegate to this constructor to make sure that the object lifetime starts. + * With this, the destructor of the object will be called, even when the remaining constructor + * throws. + */ +class NoExceptConstructor { +}; + +/** * Helper variable that checks if a pointer type can be converted into another pointer type without * issues. Possible issues are casting away const and casting a pointer to a child class. * Adding const or casting to a parent class is fine. @@ -427,4 +436,49 @@ inline constexpr int64_t default_inline_buffer_capacity(size_t element_size) return (static_cast<int64_t>(element_size) < 100) ? 4 : 0; } +/** + * This can be used by containers to implement an exception-safe copy-assignment-operator. + * It assumes that the container has an exception safe copy constructor and an exception-safe + * move-assignment-operator. + */ +template<typename Container> Container ©_assign_container(Container &dst, const Container &src) +{ + if (&src == &dst) { + return dst; + } + + Container container_copy{src}; + dst = std::move(container_copy); + return dst; +} + +/** + * This can be used by containers to implement an exception-safe move-assignment-operator. + * It assumes that the container has an exception-safe move-constructor and a noexcept constructor + * tagged with the NoExceptConstructor tag. + */ +template<typename Container> +Container &move_assign_container(Container &dst, Container &&src) noexcept( + std::is_nothrow_move_constructible_v<Container>) +{ + if (&dst == &src) { + return dst; + } + + dst.~Container(); + if constexpr (std::is_nothrow_move_constructible_v<Container>) { + new (&dst) Container(std::move(src)); + } + else { + try { + new (&dst) Container(std::move(src)); + } + catch (...) { + new (&dst) Container(NoExceptConstructor()); + throw; + } + } + return dst; +} + } // namespace blender diff --git a/source/blender/blenlib/BLI_stack.hh b/source/blender/blenlib/BLI_stack.hh index 8eca356ec54..a463ac102f1 100644 --- a/source/blender/blenlib/BLI_stack.hh +++ b/source/blender/blenlib/BLI_stack.hh @@ -117,7 +117,7 @@ class Stack { /** * Initialize an empty stack. No heap allocation is done. */ - Stack(Allocator allocator = {}) : allocator_(allocator) + Stack(Allocator allocator = {}) noexcept : allocator_(allocator) { inline_chunk_.below = nullptr; inline_chunk_.above = nullptr; @@ -129,11 +129,15 @@ class Stack { size_ = 0; } + Stack(NoExceptConstructor, Allocator allocator = {}) noexcept : Stack(allocator) + { + } + /** * Create a new stack that contains the given elements. The values are pushed to the stack in * the order they are in the array. */ - Stack(Span<T> values) : Stack() + Stack(Span<T> values, Allocator allocator = {}) : Stack(NoExceptConstructor(), allocator) { this->push_multiple(values); } @@ -147,11 +151,12 @@ class Stack { * assert(stack.pop() == 6); * assert(stack.pop() == 5); */ - Stack(const std::initializer_list<T> &values) : Stack(Span<T>(values)) + Stack(const std::initializer_list<T> &values, Allocator allocator = {}) + : Stack(Span<T>(values), allocator) { } - Stack(const Stack &other) : Stack(other.allocator_) + Stack(const Stack &other) : Stack(NoExceptConstructor(), other.allocator_) { for (const Chunk *chunk = &other.inline_chunk_; chunk; chunk = chunk->above) { const T *begin = chunk->begin; @@ -160,7 +165,8 @@ class Stack { } } - Stack(Stack &&other) noexcept : Stack(other.allocator_) + Stack(Stack &&other) noexcept(std::is_nothrow_move_constructible_v<T>) + : Stack(NoExceptConstructor(), other.allocator_) { uninitialized_relocate_n<T>( other.inline_buffer_, std::min(other.size_, InlineBufferCapacity), inline_buffer_); @@ -197,28 +203,14 @@ class Stack { } } - Stack &operator=(const Stack &stack) + Stack &operator=(const Stack &other) { - if (this == &stack) { - return *this; - } - - this->~Stack(); - new (this) Stack(stack); - - return *this; + return copy_assign_container(*this, other); } - Stack &operator=(Stack &&stack) + Stack &operator=(Stack &&other) { - if (this == &stack) { - return *this; - } - - this->~Stack(); - new (this) Stack(std::move(stack)); - - return *this; + return move_assign_container(*this, std::move(other)); } /** @@ -226,21 +218,26 @@ class Stack { */ void push(const T &value) { - if (top_ == top_chunk_->capacity_end) { - this->activate_next_chunk(1); - } - new (top_) T(value); - top_++; - size_++; + this->push_as(value); } void push(T &&value) { + this->push_as(std::move(value)); + } + template<typename ForwardT> void push_as(ForwardT &&value) + { if (top_ == top_chunk_->capacity_end) { this->activate_next_chunk(1); } - new (top_) T(std::move(value)); - top_++; - size_++; + try { + new (top_) T(std::forward<ForwardT>(value)); + top_++; + size_++; + } + catch (...) { + this->move_top_pointer_back_to_below_chunk(); + throw; + } } /** @@ -250,8 +247,8 @@ class Stack { T pop() { BLI_assert(size_ > 0); + T value = std::move(*(top_ - 1)); top_--; - T value = std::move(*top_); top_->~T(); size_--; @@ -296,13 +293,18 @@ class Stack { const int64_t remaining_capacity = top_chunk_->capacity_end - top_; const int64_t amount = std::min(remaining_values.size(), remaining_capacity); - uninitialized_copy_n(remaining_values.data(), amount, top_); + try { + uninitialized_copy_n(remaining_values.data(), amount, top_); + } + catch (...) { + this->move_top_pointer_back_to_below_chunk(); + throw; + } top_ += amount; + size_ += amount; remaining_values = remaining_values.drop_front(amount); } - - size_ += values.size(); } /** @@ -332,6 +334,15 @@ class Stack { top_ = top_chunk_->begin; } + /* This should only be called by unit tests. */ + bool is_invariant_maintained() const + { + if (size_ == 0) { + return top_ == inline_chunk_.begin; + } + return top_ > top_chunk_->begin; + } + private: /** * Changes top_chunk_ to point to a new chunk that is above the current one. The new chunk might @@ -365,6 +376,18 @@ class Stack { top_ = top_chunk_->begin; } + void move_top_pointer_back_to_below_chunk() + { + /* This makes sure that the invariant stays intact after a failed push. */ + if (size_ == 0) { + top_ = inline_chunk_.begin; + } + else if (top_ == top_chunk_->begin) { + top_chunk_ = top_chunk_->below; + top_ = top_chunk_->capacity_end; + } + } + void destruct_all_elements() { for (T *value = top_chunk_->begin; value != top_; value++) { diff --git a/source/blender/blenlib/BLI_vector.hh b/source/blender/blenlib/BLI_vector.hh index 74ce8dd42e7..392b6cd9f47 100644 --- a/source/blender/blenlib/BLI_vector.hh +++ b/source/blender/blenlib/BLI_vector.hh @@ -118,7 +118,7 @@ class Vector { * Create an empty vector. * This does not do any memory allocation. */ - Vector(Allocator allocator = {}) : allocator_(allocator) + Vector(Allocator allocator = {}) noexcept : allocator_(allocator) { begin_ = inline_buffer_; end_ = begin_; @@ -126,12 +126,17 @@ class Vector { UPDATE_VECTOR_SIZE(this); } + Vector(NoExceptConstructor, Allocator allocator = {}) noexcept : Vector(allocator) + { + } + /** * Create a vector with a specific size. * The elements will be default constructed. * If T is trivially constructible, the elements in the vector are not touched. */ - explicit Vector(int64_t size) : Vector() + explicit Vector(int64_t size, Allocator allocator = {}) + : Vector(NoExceptConstructor(), allocator) { this->resize(size); } @@ -139,7 +144,8 @@ class Vector { /** * Create a vector filled with a specific value. */ - Vector(int64_t size, const T &value) : Vector() + Vector(int64_t size, const T &value, Allocator allocator = {}) + : Vector(NoExceptConstructor(), allocator) { this->resize(size, value); } @@ -148,12 +154,12 @@ class Vector { * Create a vector from an array ref. The values in the vector are copy constructed. */ template<typename U, typename std::enable_if_t<std::is_convertible_v<U, T>> * = nullptr> - Vector(Span<U> values, Allocator allocator = {}) : Vector(allocator) + Vector(Span<U> values, Allocator allocator = {}) : Vector(NoExceptConstructor(), allocator) { const int64_t size = values.size(); this->reserve(size); - this->increase_size_by_unchecked(size); uninitialized_convert_n<U, T>(values.data(), size, begin_); + this->increase_size_by_unchecked(size); } /** @@ -182,7 +188,8 @@ class Vector { /* This constructor should not be called with e.g. Vector(3, 10), because that is expected to produce the vector (10, 10, 10). */ typename std::enable_if_t<!std::is_convertible_v<InputIt, int>> * = nullptr> - Vector(InputIt first, InputIt last, Allocator allocator = {}) : Vector(std::move(allocator)) + Vector(InputIt first, InputIt last, Allocator allocator = {}) + : Vector(NoExceptConstructor(), allocator) { for (InputIt current = first; current != last; ++current) { this->append(*current); @@ -196,7 +203,7 @@ class Vector { * Example Usage: * Vector<ModifierData *> modifiers(ob->modifiers); */ - Vector(ListBase &values) : Vector() + Vector(ListBase &values, Allocator allocator = {}) : Vector(NoExceptConstructor(), allocator) { LISTBASE_FOREACH (T, value, &values) { this->append(value); @@ -226,27 +233,26 @@ class Vector { * have zero elements afterwards. */ template<int64_t OtherInlineBufferCapacity> - Vector(Vector<T, OtherInlineBufferCapacity, Allocator> &&other) noexcept - : allocator_(other.allocator_) + Vector(Vector<T, OtherInlineBufferCapacity, Allocator> &&other) noexcept( + std::is_nothrow_move_constructible_v<T>) + : Vector(NoExceptConstructor(), other.allocator_) { const int64_t size = other.size(); if (other.is_inline()) { if (size <= InlineBufferCapacity) { /* Copy between inline buffers. */ - begin_ = inline_buffer_; - end_ = begin_ + size; - capacity_end_ = begin_ + InlineBufferCapacity; uninitialized_relocate_n(other.begin_, size, begin_); + end_ = begin_ + size; } else { /* Copy from inline buffer to newly allocated buffer. */ const int64_t capacity = size; begin_ = static_cast<T *>( allocator_.allocate(sizeof(T) * static_cast<size_t>(capacity), alignof(T), AT)); - end_ = begin_ + size; capacity_end_ = begin_ + capacity; uninitialized_relocate_n(other.begin_, size, begin_); + end_ = begin_ + size; } } else { @@ -273,28 +279,12 @@ class Vector { Vector &operator=(const Vector &other) { - if (this == &other) { - return *this; - } - - this->~Vector(); - new (this) Vector(other); - - return *this; + return copy_assign_container(*this, other); } Vector &operator=(Vector &&other) { - if (this == &other) { - return *this; - } - - /* This can be incorrect, when the vector is used to build a recursive data structure. However, - we don't take care of it at this low level. See https://youtu.be/7Qgd9B1KuMQ?t=840. */ - this->~Vector(); - new (this) Vector(std::move(other)); - - return *this; + return move_assign_container(*this, std::move(other)); } /** @@ -474,17 +464,10 @@ class Vector { * behavior when not enough capacity has been reserved beforehand. Only use this in performance * critical code. */ - void append_unchecked(const T &value) - { - BLI_assert(end_ < capacity_end_); - new (end_) T(value); - end_++; - UPDATE_VECTOR_SIZE(this); - } - void append_unchecked(T &&value) + template<typename ForwardT> void append_unchecked(ForwardT &&value) { BLI_assert(end_ < capacity_end_); - new (end_) T(std::move(value)); + new (end_) T(std::forward<ForwardT>(value)); end_++; UPDATE_VECTOR_SIZE(this); } @@ -497,7 +480,7 @@ class Vector { { BLI_assert(n >= 0); this->reserve(this->size() + n); - blender::uninitialized_fill_n(end_, n, value); + uninitialized_fill_n(end_, n, value); this->increase_size_by_unchecked(n); } @@ -507,7 +490,7 @@ class Vector { * useful when you want to call constructors in the vector yourself. This should only be done in * very rare cases and has to be justified every time. */ - void increase_size_by_unchecked(const int64_t n) + void increase_size_by_unchecked(const int64_t n) noexcept { BLI_assert(end_ + n <= capacity_end_); end_ += n; @@ -553,7 +536,7 @@ class Vector { { BLI_assert(amount >= 0); BLI_assert(begin_ + amount <= capacity_end_); - blender::uninitialized_copy_n(start, amount, end_); + uninitialized_copy_n(start, amount, end_); end_ += amount; UPDATE_VECTOR_SIZE(this); } @@ -600,11 +583,29 @@ class Vector { for (int64_t i = 0; i < move_amount; i++) { const int64_t src_index = insert_index + move_amount - i - 1; const int64_t dst_index = new_size - i - 1; - new (static_cast<void *>(begin_ + dst_index)) T(std::move(begin_[src_index])); + try { + new (static_cast<void *>(begin_ + dst_index)) T(std::move(begin_[src_index])); + } + catch (...) { + /* Destruct all values that have been moved already. */ + destruct_n(begin_ + dst_index + 1, i); + end_ = begin_ + src_index + 1; + UPDATE_VECTOR_SIZE(this); + throw; + } begin_[src_index].~T(); } - std::uninitialized_copy_n(first, insert_amount, begin_ + insert_index); + try { + std::uninitialized_copy_n(first, insert_amount, begin_ + insert_index); + } + catch (...) { + /* Destruct all values that have been moved. */ + destruct_n(begin_ + new_size - move_amount, move_amount); + end_ = begin_ + insert_index; + UPDATE_VECTOR_SIZE(this); + throw; + } end_ = begin_ + new_size; UPDATE_VECTOR_SIZE(this); } @@ -686,8 +687,8 @@ class Vector { T pop_last() { BLI_assert(!this->is_empty()); + T value = std::move(*(end_ - 1)); end_--; - T value = std::move(*end_); end_->~T(); UPDATE_VECTOR_SIZE(this); return value; @@ -702,10 +703,10 @@ class Vector { BLI_assert(index >= 0); BLI_assert(index < this->size()); T *element_to_remove = begin_ + index; - end_--; if (element_to_remove < end_) { - *element_to_remove = std::move(*end_); + *element_to_remove = std::move(*(end_ - 1)); } + end_--; end_->~T(); UPDATE_VECTOR_SIZE(this); } @@ -901,7 +902,13 @@ class Vector { T *new_array = static_cast<T *>( allocator_.allocate(static_cast<size_t>(new_capacity) * sizeof(T), alignof(T), AT)); - uninitialized_relocate_n(begin_, size, new_array); + try { + uninitialized_relocate_n(begin_, size, new_array); + } + catch (...) { + allocator_.deallocate(new_array); + throw; + } if (!this->is_inline()) { allocator_.deallocate(begin_); diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index 819c74b6946..2f1c3436806 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -390,6 +390,8 @@ if(WITH_GTESTS) tests/BLI_task_test.cc tests/BLI_vector_set_test.cc tests/BLI_vector_test.cc + + tests/BLI_exception_safety_test_utils.hh ) set(TEST_INC ../imbuf diff --git a/source/blender/blenlib/intern/delaunay_2d.c b/source/blender/blenlib/intern/delaunay_2d.c index baf49ddaffd..ee22859c1d6 100644 --- a/source/blender/blenlib/intern/delaunay_2d.c +++ b/source/blender/blenlib/intern/delaunay_2d.c @@ -3378,6 +3378,9 @@ CDT_result *BLI_delaunay_2d_cdt_calc(const CDT_input *input, const CDT_output_ty if (input != input_orig) { free_modified_input((CDT_input *)input); } + if (new_edge_map != NULL) { + MEM_freeN(new_edge_map); + } new_cdt_free(cdt); return result; } diff --git a/source/blender/blenlib/intern/freetypefont.c b/source/blender/blenlib/intern/freetypefont.c index 34886054cb0..301d9dc2296 100644 --- a/source/blender/blenlib/intern/freetypefont.c +++ b/source/blender/blenlib/intern/freetypefont.c @@ -15,7 +15,8 @@ * * The Original Code is written by Rob Haarsma (phase) * All rights reserved. - * This code parses the Freetype font outline data to chains of Blender's beziertriples. + * + * This code parses the Freetype font outline data to chains of Blender's bezier-triples. * Additional information can be found at the bottom of this file. * * Code that uses exotic character maps is present but commented out. diff --git a/source/blender/blenlib/tests/BLI_array_test.cc b/source/blender/blenlib/tests/BLI_array_test.cc index 38ab695d238..251cff833f7 100644 --- a/source/blender/blenlib/tests/BLI_array_test.cc +++ b/source/blender/blenlib/tests/BLI_array_test.cc @@ -1,6 +1,7 @@ /* Apache License, Version 2.0 */ #include "BLI_array.hh" +#include "BLI_exception_safety_test_utils.hh" #include "BLI_strict_flags.h" #include "BLI_vector.hh" #include "testing/testing.h" @@ -188,4 +189,42 @@ TEST(array, ReverseIterator) EXPECT_EQ_ARRAY(array.data(), Span({13, 14, 15, 16}).data(), 4); } +TEST(array, SpanConstructorExceptions) +{ + std::array<ExceptionThrower, 4> values; + values[2].throw_during_copy = true; + Span<ExceptionThrower> span{values}; + EXPECT_ANY_THROW({ Array<ExceptionThrower> array(span); }); +} + +TEST(array, SizeValueConstructorExceptions) +{ + ExceptionThrower value; + value.throw_during_copy = true; + EXPECT_ANY_THROW({ Array<ExceptionThrower> array(5, value); }); +} + +TEST(array, MoveConstructorExceptions) +{ + Array<ExceptionThrower, 4> array(3); + array[1].throw_during_move = true; + EXPECT_ANY_THROW({ Array<ExceptionThrower> array_copy(std::move(array)); }); +} + +TEST(array, CopyAssignmentExceptions) +{ + Array<ExceptionThrower> array(5); + array[3].throw_during_copy = true; + Array<ExceptionThrower> array_copy(10); + EXPECT_ANY_THROW({ array_copy = array; }); +} + +TEST(array, MoveAssignmentExceptions) +{ + Array<ExceptionThrower, 4> array(4); + array[2].throw_during_move = true; + Array<ExceptionThrower> array_moved(10); + EXPECT_ANY_THROW({ array_moved = std::move(array); }); +} + } // namespace blender::tests diff --git a/source/blender/blenlib/tests/BLI_exception_safety_test_utils.hh b/source/blender/blenlib/tests/BLI_exception_safety_test_utils.hh new file mode 100644 index 00000000000..5ad7674396b --- /dev/null +++ b/source/blender/blenlib/tests/BLI_exception_safety_test_utils.hh @@ -0,0 +1,72 @@ +#include "BLI_utildefines.h" +#include "MEM_guardedalloc.h" +#include "testing/testing.h" + +namespace blender::tests { + +class ExceptionThrower { + private: + /* Use some random values that are unlikely to exist at the memory location already. */ + static constexpr uint32_t is_alive_state = 0x21254634; + static constexpr uint32_t is_destructed_state = 0xFA4BC327; + + uint32_t state_; + + /* Make use of leak detector to check if this value has been destructed. */ + void *my_memory_; + + public: + bool throw_during_copy; + bool throw_during_move; + + ExceptionThrower() + : state_(is_alive_state), + my_memory_(MEM_mallocN(1, AT)), + throw_during_copy(false), + throw_during_move(false) + { + } + + ExceptionThrower(const ExceptionThrower &other) : ExceptionThrower() + { + EXPECT_EQ(other.state_, is_alive_state); + if (other.throw_during_copy) { + throw std::runtime_error("throwing during copy, as requested"); + } + } + + ExceptionThrower(ExceptionThrower &&other) : ExceptionThrower() + { + EXPECT_EQ(other.state_, is_alive_state); + if (other.throw_during_move) { + throw std::runtime_error("throwing during move, as requested"); + } + } + + ExceptionThrower &operator=(const ExceptionThrower &other) + { + EXPECT_EQ(other.state_, is_alive_state); + if (throw_during_copy || other.throw_during_copy) { + throw std::runtime_error("throwing during copy, as requested"); + } + return *this; + } + + ExceptionThrower &operator=(ExceptionThrower &&other) + { + EXPECT_EQ(other.state_, is_alive_state); + if (throw_during_move || other.throw_during_move) { + throw std::runtime_error("throwing during move, as requested"); + } + return *this; + } + + ~ExceptionThrower() + { + EXPECT_EQ(state_, is_alive_state); + state_ = is_destructed_state; + MEM_freeN(my_memory_); + } +}; + +} // namespace blender::tests diff --git a/source/blender/blenlib/tests/BLI_memory_utils_test.cc b/source/blender/blenlib/tests/BLI_memory_utils_test.cc index f3cb02b63d7..fcef2f8688a 100644 --- a/source/blender/blenlib/tests/BLI_memory_utils_test.cc +++ b/source/blender/blenlib/tests/BLI_memory_utils_test.cc @@ -7,6 +7,7 @@ namespace blender::tests { +namespace { struct MyValue { static inline int alive = 0; @@ -33,6 +34,7 @@ struct MyValue { alive--; } }; +} // namespace TEST(memory_utils, DefaultConstructN_ActuallyCallsConstructor) { diff --git a/source/blender/blenlib/tests/BLI_stack_cxx_test.cc b/source/blender/blenlib/tests/BLI_stack_cxx_test.cc index 3572e751b88..c03893c5596 100644 --- a/source/blender/blenlib/tests/BLI_stack_cxx_test.cc +++ b/source/blender/blenlib/tests/BLI_stack_cxx_test.cc @@ -1,5 +1,6 @@ /* Apache License, Version 2.0 */ +#include "BLI_exception_safety_test_utils.hh" #include "BLI_stack.hh" #include "BLI_strict_flags.h" #include "BLI_vector.hh" @@ -185,4 +186,59 @@ TEST(stack, OveralignedValues) } } +TEST(stack, SpanConstructorExceptions) +{ + std::array<ExceptionThrower, 5> values; + values[3].throw_during_copy = true; + EXPECT_ANY_THROW({ Stack<ExceptionThrower> stack(values); }); +} + +TEST(stack, MoveConstructorExceptions) +{ + Stack<ExceptionThrower, 4> stack; + stack.push({}); + stack.push({}); + stack.peek().throw_during_move = true; + EXPECT_ANY_THROW({ Stack<ExceptionThrower> moved_stack{std::move(stack)}; }); +} + +TEST(stack, PushExceptions) +{ + Stack<ExceptionThrower, 2> stack; + stack.push({}); + stack.push({}); + ExceptionThrower *ptr1 = &stack.peek(); + ExceptionThrower value; + value.throw_during_copy = true; + EXPECT_ANY_THROW({ stack.push(value); }); + EXPECT_EQ(stack.size(), 2); + ExceptionThrower *ptr2 = &stack.peek(); + EXPECT_EQ(ptr1, ptr2); + EXPECT_TRUE(stack.is_invariant_maintained()); +} + +TEST(stack, PopExceptions) +{ + Stack<ExceptionThrower> stack; + stack.push({}); + stack.peek().throw_during_move = true; + stack.push({}); + stack.pop(); /* NOLINT: bugprone-throw-keyword-missing */ + EXPECT_ANY_THROW({ stack.pop(); }); /* NOLINT: bugprone-throw-keyword-missing */ + EXPECT_EQ(stack.size(), 1); + EXPECT_TRUE(stack.is_invariant_maintained()); +} + +TEST(stack, PushMultipleExceptions) +{ + Stack<ExceptionThrower> stack; + stack.push({}); + std::array<ExceptionThrower, 100> values; + values[6].throw_during_copy = true; + EXPECT_ANY_THROW({ stack.push_multiple(values); }); + EXPECT_TRUE(stack.is_invariant_maintained()); + EXPECT_ANY_THROW({ stack.push_multiple(values); }); + EXPECT_TRUE(stack.is_invariant_maintained()); +} + } // namespace blender::tests diff --git a/source/blender/blenlib/tests/BLI_vector_test.cc b/source/blender/blenlib/tests/BLI_vector_test.cc index 792e120d2c0..056a7aa3924 100644 --- a/source/blender/blenlib/tests/BLI_vector_test.cc +++ b/source/blender/blenlib/tests/BLI_vector_test.cc @@ -1,5 +1,6 @@ /* Apache License, Version 2.0 */ +#include "BLI_exception_safety_test_utils.hh" #include "BLI_strict_flags.h" #include "BLI_vector.hh" #include "testing/testing.h" @@ -709,4 +710,87 @@ TEST(vector, ReverseIterator) EXPECT_EQ_ARRAY(reversed_vec.data(), Span({7, 6, 5, 4}).data(), 4); } +TEST(vector, SizeValueConstructorExceptions) +{ + ExceptionThrower value; + value.throw_during_copy = true; + EXPECT_ANY_THROW({ Vector<ExceptionThrower> vec(5, value); }); +} + +TEST(vector, SpanConstructorExceptions) +{ + std::array<ExceptionThrower, 5> values; + values[3].throw_during_copy = true; + EXPECT_ANY_THROW({ Vector<ExceptionThrower> vec(values); }); +} + +TEST(vector, MoveConstructorExceptions) +{ + Vector<ExceptionThrower, 4> vec(3); + vec[2].throw_during_move = true; + EXPECT_ANY_THROW({ Vector<ExceptionThrower> moved_vector{std::move(vec)}; }); +} + +TEST(vector, AppendExceptions) +{ + Vector<ExceptionThrower, 4> vec(2); + ExceptionThrower *ptr1 = &vec.last(); + ExceptionThrower value; + value.throw_during_copy = true; + EXPECT_ANY_THROW({ vec.append(value); }); + EXPECT_EQ(vec.size(), 2); + ExceptionThrower *ptr2 = &vec.last(); + EXPECT_EQ(ptr1, ptr2); +} + +TEST(vector, ExtendExceptions) +{ + Vector<ExceptionThrower> vec(5); + std::array<ExceptionThrower, 10> values; + values[6].throw_during_copy = true; + EXPECT_ANY_THROW({ vec.extend(values); }); + EXPECT_EQ(vec.size(), 5); +} + +TEST(vector, Insert1Exceptions) +{ + Vector<ExceptionThrower> vec(10); + std::array<ExceptionThrower, 5> values; + values[3].throw_during_copy = true; + EXPECT_ANY_THROW({ vec.insert(7, values); }); +} + +TEST(vector, Insert2Exceptions) +{ + Vector<ExceptionThrower> vec(10); + vec.reserve(100); + vec[8].throw_during_move = true; + std::array<ExceptionThrower, 5> values; + EXPECT_ANY_THROW({ vec.insert(3, values); }); +} + +TEST(vector, PopLastExceptions) +{ + Vector<ExceptionThrower> vec(10); + vec.last().throw_during_move = true; + EXPECT_ANY_THROW({ vec.pop_last(); }); /* NOLINT: bugprone-throw-keyword-missing */ + EXPECT_EQ(vec.size(), 10); +} + +TEST(vector, RemoveAndReorderExceptions) +{ + Vector<ExceptionThrower> vec(10); + vec.last().throw_during_move = true; + EXPECT_ANY_THROW({ vec.remove_and_reorder(3); }); + EXPECT_EQ(vec.size(), 10); +} + +TEST(vector, RemoveExceptions) +{ + Vector<ExceptionThrower> vec(10); + vec[8].throw_during_move = true; + EXPECT_ANY_THROW({ vec.remove(2); }); + EXPECT_EQ(vec.size(), 10); +} + } // namespace blender::tests diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 0d8f2eac99e..5107b530b08 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -3413,7 +3413,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) } case SPACE_OUTLINER: { SpaceOutliner *space_outliner = (SpaceOutliner *)sl; - space_outliner->filter &= ~(SO_FILTER_UNUSED_1 | SO_FILTER_UNUSED_5 | + space_outliner->filter &= ~(SO_FILTER_UNUSED_1 | SO_FILTER_NO_ROW_CHILDREN | SO_FILTER_UNUSED_12); space_outliner->storeflag &= ~(SO_TREESTORE_UNUSED_1); break; diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c index bc13e3b3a39..5fce442cd34 100644 --- a/source/blender/blenloader/intern/versioning_290.c +++ b/source/blender/blenloader/intern/versioning_290.c @@ -208,6 +208,17 @@ void do_versions_after_linking_290(Main *bmain, ReportList *UNUSED(reports)) } } + if (!MAIN_VERSION_ATLEAST(bmain, 291, 1)) { + LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { + if (BKE_collection_cycles_fix(bmain, collection)) { + printf( + "WARNING: Cycle detected in collection '%s', fixed as best as possible.\n" + "You may have to reconstruct your View Layers...\n", + collection->id.name); + } + } + } + /** * Versioning code until next subversion bump goes here. * @@ -219,18 +230,26 @@ void do_versions_after_linking_290(Main *bmain, ReportList *UNUSED(reports)) * \note Keep this message at the bottom of the function. */ { - LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { - if (BKE_collection_cycles_fix(bmain, collection)) { - printf( - "WARNING: Cycle detected in collection '%s', fixed as best as possible.\n" - "You may have to reconstruct your View Layers...\n", - collection->id.name); - } - } + /* Keep this block, even when empty. */ } } +static void panels_remove_x_closed_flag_recursive(Panel *panel) +{ + const bool was_closed_x = panel->flag & PNL_UNUSED_1; + const bool was_closed_y = panel->flag & PNL_CLOSED; /* That value was the Y closed flag. */ + + SET_FLAG_FROM_TEST(panel->flag, was_closed_x || was_closed_y, PNL_CLOSED); + + /* Clear the old PNL_CLOSEDX flag. */ + panel->flag &= ~PNL_UNUSED_1; + + LISTBASE_FOREACH (Panel *, child_panel, &panel->children) { + panels_remove_x_closed_flag_recursive(child_panel); + } +} + void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) { UNUSED_VARS(fd); @@ -409,17 +428,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) } } - /** - * Versioning code until next subversion bump goes here. - * - * \note Be sure to check when bumping the version: - * - "versioning_userdef.c", #BLO_version_defaults_userpref_blend - * - "versioning_userdef.c", #do_versions_theme - * - * \note Keep this message at the bottom of the function. - */ - { - /* Keep this block, even when empty. */ + if (!MAIN_VERSION_ATLEAST(bmain, 291, 1)) { /* Initialize additional parameter of the Nishita sky model and change altitude unit. */ if (!DNA_struct_elem_find(fd->filesdna, "NodeTexSky", "float", "sun_intensity")) { @@ -484,5 +493,41 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) } } } + + /* Remove panel X axis collapsing, a remnant of horizontal panel alignment. */ + LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { + LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { + panels_remove_x_closed_flag_recursive(panel); + } + } + } + } + } + + /** + * Versioning code until next subversion bump goes here. + * + * \note Be sure to check when bumping the version: + * - "versioning_userdef.c", #BLO_version_defaults_userpref_blend + * - "versioning_userdef.c", #do_versions_theme + * + * \note Keep this message at the bottom of the function. + */ + { + /* Keep this block, even when empty. */ + + for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, space, &area->spacedata) { + if (space->spacetype == SPACE_OUTLINER) { + SpaceOutliner *space_outliner = (SpaceOutliner *)space; + + space_outliner->flag |= SO_MODE_COLUMN; + } + } + } + } } } diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c index 475f618b1f4..76e9ab95732 100644 --- a/source/blender/blenloader/intern/versioning_userdef.c +++ b/source/blender/blenloader/intern/versioning_userdef.c @@ -767,6 +767,12 @@ void BLO_version_defaults_userpref_blend(Main *bmain, UserDef *userdef) userdef->statusbar_flag = STATUSBAR_SHOW_VERSION; } + if (!USER_VERSION_ATLEAST(291, 1)) { + if (userdef->collection_instance_empty_size == 0) { + userdef->collection_instance_empty_size = 1.0f; + } + } + /** * Versioning code until next subversion bump goes here. * @@ -778,10 +784,6 @@ void BLO_version_defaults_userpref_blend(Main *bmain, UserDef *userdef) */ { /* Keep this block, even when empty. */ - - if (userdef->collection_instance_empty_size == 0) { - userdef->collection_instance_empty_size = 1.0f; - } } if (userdef->pixelsize == 0.0f) { diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h index 8f33e9f480d..0ded511b8f8 100644 --- a/source/blender/depsgraph/DEG_depsgraph.h +++ b/source/blender/depsgraph/DEG_depsgraph.h @@ -127,6 +127,12 @@ void DEG_graph_id_tag_update(struct Main *bmain, struct ID *id, int flag); +/* Tag all dependency graphs when time has changed. */ +void DEG_time_tag_update(struct Main *bmain); + +/* Tag a dependency graph when time has changed. */ +void DEG_graph_time_tag_update(struct Depsgraph *depsgraph); + /* Mark a particular datablock type as having changing. This does * not cause any updates but is used by external render engines to detect if for * example a datablock was removed. */ @@ -155,8 +161,6 @@ void DEG_evaluate_on_framechange(Depsgraph *graph, float ctime); /* Data changed recalculation entry point. */ void DEG_evaluate_on_refresh(Depsgraph *graph); -bool DEG_needs_eval(Depsgraph *graph); - /* Editors Integration -------------------------- */ /* Mechanism to allow editors to be informed of depsgraph updates, diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 37b23833e00..c0b692f28c1 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -978,13 +978,13 @@ void DepsgraphRelationBuilder::build_object_parent(Object *object) break; } } - /* Metaballs are the odd balls here (no pun intended): they will request + /* Meta-balls are the odd balls here (no pun intended): they will request * instance-list (formerly known as dupli-list) during evaluation. This is * their way of interacting with all instanced surfaces, making a nice * effect when is used form particle system. */ if (object->type == OB_MBALL && parent->transflag & OB_DUPLI) { ComponentKey parent_geometry_key(parent_id, NodeType::GEOMETRY); - /* NOTE: Metaballs are evaluating geometry only after their transform, + /* NOTE: Meta-balls are evaluating geometry only after their transform, * so we only hook up to transform channel here. */ add_relation(parent_geometry_key, object_transform_key, "Parent"); } diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc index 4a9c840dd9f..c0feab2262a 100644 --- a/source/blender/depsgraph/intern/depsgraph.cc +++ b/source/blender/depsgraph/intern/depsgraph.cc @@ -63,7 +63,6 @@ namespace deg { Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode) : time_source(nullptr), need_update(true), - need_update_time(false), bmain(bmain), scene(scene), view_layer(view_layer), @@ -103,6 +102,11 @@ TimeSourceNode *Depsgraph::find_time_source() const return time_source; } +void Depsgraph::tag_time_source() +{ + time_source->tag_update(this, DEG_UPDATE_SOURCE_TIME); +} + IDNode *Depsgraph::find_id_node(const ID *id) const { return id_hash.lookup_default(id, nullptr); diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h index ea579a4958e..e03846f81e2 100644 --- a/source/blender/depsgraph/intern/depsgraph.h +++ b/source/blender/depsgraph/intern/depsgraph.h @@ -68,6 +68,7 @@ struct Depsgraph { TimeSourceNode *add_time_source(); TimeSourceNode *find_time_source() const; + void tag_time_source(); IDNode *find_id_node(const ID *id) const; IDNode *add_id_node(ID *id, ID *id_cow_hint = nullptr); @@ -121,10 +122,6 @@ struct Depsgraph { /* Nodes which have been tagged as "directly modified". */ Set<OperationNode *> entry_tags; - /* Special entry tag for time source. Allows to tag invisible dependency graphs for update when - * scene frame changes, so then when dependency graph becomes visible it is on a proper state. */ - bool need_update_time; - /* Convenience Data ................... */ /* XXX: should be collected after building (if actually needed?) */ diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc index 0c116f5863c..1ad3fdbc9da 100644 --- a/source/blender/depsgraph/intern/depsgraph_eval.cc +++ b/source/blender/depsgraph/intern/depsgraph_eval.cc @@ -47,38 +47,37 @@ namespace deg = blender::deg; -/* Evaluate all nodes tagged for updating. */ -void DEG_evaluate_on_refresh(Depsgraph *graph) +static void deg_flush_updates_and_refresh(deg::Depsgraph *deg_graph) { - deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(graph); - deg_graph->ctime = BKE_scene_frame_get(deg_graph->scene); - /* Update time in scene. */ + /* Update the time on the cow scene. */ if (deg_graph->scene_cow) { BKE_scene_frame_set(deg_graph->scene_cow, deg_graph->ctime); } + deg::deg_graph_flush_updates(deg_graph); deg::deg_evaluate_on_refresh(deg_graph); - deg_graph->need_update_time = false; } -/* Frame-change happened for root scene that graph belongs to. */ -void DEG_evaluate_on_framechange(Depsgraph *graph, float ctime) +/* Evaluate all nodes tagged for updating. */ +void DEG_evaluate_on_refresh(Depsgraph *graph) { deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(graph); - deg_graph->ctime = ctime; - deg_graph->need_update_time = true; - deg::deg_graph_flush_updates(deg_graph); - /* Update time in scene. */ - if (deg_graph->scene_cow) { - BKE_scene_frame_set(deg_graph->scene_cow, deg_graph->ctime); + const Scene *scene = DEG_get_input_scene(graph); + const float ctime = BKE_scene_frame_get(scene); + + if (ctime != deg_graph->ctime) { + deg_graph->tag_time_source(); + deg_graph->ctime = ctime; } - /* Perform recalculation updates. */ - deg::deg_evaluate_on_refresh(deg_graph); - deg_graph->need_update_time = false; + + deg_flush_updates_and_refresh(deg_graph); } -bool DEG_needs_eval(Depsgraph *graph) +/* Frame-change happened for root scene that graph belongs to. */ +void DEG_evaluate_on_framechange(Depsgraph *graph, float ctime) { deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(graph); - return !deg_graph->entry_tags.is_empty() || deg_graph->need_update_time; + deg_graph->tag_time_source(); + deg_graph->ctime = ctime; + deg_flush_updates_and_refresh(deg_graph); } diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index 4a2d47f9379..868f88d8fcd 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -66,6 +66,7 @@ #include "intern/node/deg_node_factory.h" #include "intern/node/deg_node_id.h" #include "intern/node/deg_node_operation.h" +#include "intern/node/deg_node_time.h" namespace deg = blender::deg; @@ -230,9 +231,6 @@ void depsgraph_tag_to_component_opcode(const ID *id, case ID_RECALC_SOURCE: *component_type = NodeType::PARAMETERS; break; - case ID_RECALC_TIME: - BLI_assert(!"Should be handled outside of this function"); - break; case ID_RECALC_ALL: case ID_RECALC_PSYS_ALL: BLI_assert(!"Should not happen"); @@ -372,12 +370,6 @@ void graph_id_tag_update_single_flag(Main *bmain, } return; } - if (tag == ID_RECALC_TIME) { - if (graph != nullptr) { - graph->need_update_time = true; - } - return; - } /* Get description of what is to be tagged. */ NodeType component_type; OperationCode operation_code; @@ -462,8 +454,8 @@ const char *update_source_as_string(eUpdateSource source) int deg_recalc_flags_for_legacy_zero() { - return ID_RECALC_ALL & ~(ID_RECALC_PSYS_ALL | ID_RECALC_ANIMATION | ID_RECALC_SOURCE | - ID_RECALC_TIME | ID_RECALC_EDITORS); + return ID_RECALC_ALL & + ~(ID_RECALC_PSYS_ALL | ID_RECALC_ANIMATION | ID_RECALC_SOURCE | ID_RECALC_EDITORS); } int deg_recalc_flags_effective(Depsgraph *graph, int flags) @@ -734,8 +726,6 @@ const char *DEG_update_tag_as_string(IDRecalcFlag flag) return "AUDIO"; case ID_RECALC_PARAMETERS: return "PARAMETERS"; - case ID_RECALC_TIME: - return "TIME"; case ID_RECALC_SOURCE: return "SOURCE"; case ID_RECALC_ALL: @@ -772,6 +762,19 @@ void DEG_graph_id_tag_update(struct Main *bmain, deg::graph_id_tag_update(bmain, graph, id, flag, deg::DEG_UPDATE_SOURCE_USER_EDIT); } +void DEG_time_tag_update(struct Main *bmain) +{ + for (deg::Depsgraph *depsgraph : deg::get_all_registered_graphs(bmain)) { + DEG_graph_time_tag_update(reinterpret_cast<::Depsgraph *>(depsgraph)); + } +} + +void DEG_graph_time_tag_update(struct Depsgraph *depsgraph) +{ + deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(depsgraph); + deg_graph->tag_time_source(); +} + /* Mark a particular datablock type as having changing. */ void DEG_graph_id_type_tag(Depsgraph *depsgraph, short id_type) { diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc index 1ede2cf914a..2e0487bfca1 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval.cc @@ -86,8 +86,8 @@ enum class EvaluationStage { /* Workaround for areas which can not be evaluated in threads. * - * For example, metaballs, which are iterating over all bases and are requesting dupli-lists - * to see whether there are metaballs inside. */ + * For example, meta-balls, which are iterating over all bases and are requesting dupli-lists + * to see whether there are meta-balls inside. */ SINGLE_THREADED_WORKAROUND, }; diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc index dea23c9f96d..5ccdcbec858 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc @@ -357,14 +357,9 @@ void deg_graph_flush_updates(Depsgraph *graph) BLI_assert(graph != nullptr); Main *bmain = graph->bmain; + graph->time_source->flush_update_tag(graph); + /* Nothing to update, early out. */ - if (graph->need_update_time) { - const Scene *scene_orig = graph->scene; - const float ctime = BKE_scene_frame_get(scene_orig); - TimeSourceNode *time_source = graph->find_time_source(); - graph->ctime = ctime; - time_source->tag_update(graph, DEG_UPDATE_SOURCE_TIME); - } if (graph->entry_tags.is_empty()) { return; } @@ -412,6 +407,8 @@ void deg_graph_clear_tags(Depsgraph *graph) } /* Clear any entry tags which haven't been flushed. */ graph->entry_tags.clear(); + + graph->time_source->tagged_for_update = false; } } // namespace deg diff --git a/source/blender/depsgraph/intern/node/deg_node_time.cc b/source/blender/depsgraph/intern/node/deg_node_time.cc index af931fbae34..4f7f70fef33 100644 --- a/source/blender/depsgraph/intern/node/deg_node_time.cc +++ b/source/blender/depsgraph/intern/node/deg_node_time.cc @@ -31,8 +31,16 @@ namespace blender { namespace deg { -void TimeSourceNode::tag_update(Depsgraph *graph, eUpdateSource /*source*/) +void TimeSourceNode::tag_update(Depsgraph * /*graph*/, eUpdateSource /*source*/) { + tagged_for_update = true; +} + +void TimeSourceNode::flush_update_tag(Depsgraph *graph) +{ + if (!tagged_for_update) { + return; + } for (Relation *rel : outlinks) { Node *node = rel->to; node->tag_update(graph, DEG_UPDATE_SOURCE_TIME); diff --git a/source/blender/depsgraph/intern/node/deg_node_time.h b/source/blender/depsgraph/intern/node/deg_node_time.h index fe17684abb0..79ad92f336f 100644 --- a/source/blender/depsgraph/intern/node/deg_node_time.h +++ b/source/blender/depsgraph/intern/node/deg_node_time.h @@ -30,10 +30,14 @@ namespace deg { /* Time Source Node. */ struct TimeSourceNode : public Node { + bool tagged_for_update = false; + // TODO: evaluate() operation needed virtual void tag_update(Depsgraph *graph, eUpdateSource source) override; + void flush_update_tag(Depsgraph *graph); + DEG_DEPSNODE_DECLARE; }; diff --git a/source/blender/draw/intern/draw_cache_impl_curve.c b/source/blender/draw/intern/draw_cache_impl_curve.c index 73e0ff7ef83..b93c782a5b9 100644 --- a/source/blender/draw/intern/draw_cache_impl_curve.c +++ b/source/blender/draw/intern/draw_cache_impl_curve.c @@ -307,7 +307,7 @@ static int curve_render_data_normal_len_get(const CurveRenderData *rdata) return rdata->normal.len; } -static void curve_cd_calc_used_gpu_layers(int *cd_layers, +static void curve_cd_calc_used_gpu_layers(CustomDataMask *cd_layers, struct GPUMaterial **gpumat_array, int gpumat_array_len) { @@ -334,16 +334,16 @@ static void curve_cd_calc_used_gpu_layers(int *cd_layers, switch (type) { case CD_MTFACE: - *cd_layers |= CD_MLOOPUV; + *cd_layers |= CD_MASK_MLOOPUV; break; case CD_TANGENT: - *cd_layers |= CD_TANGENT; + *cd_layers |= CD_MASK_TANGENT; break; case CD_MCOL: /* Curve object don't have Color data. */ break; case CD_ORCO: - *cd_layers |= CD_ORCO; + *cd_layers |= CD_MASK_ORCO; break; } } @@ -397,7 +397,7 @@ typedef struct CurveBatchCache { GPUIndexBuf **surf_per_mat_tris; GPUBatch **surf_per_mat; int mat_len; - int cd_used, cd_needed; + CustomDataMask cd_used, cd_needed; /* settings to determine if cache is invalid */ bool is_dirty; @@ -998,10 +998,10 @@ void DRW_curve_batch_cache_create_requested(Object *ob) if (cache->mat_len > 1) { DRW_ibo_request(cache->surf_per_mat[i], &cache->surf_per_mat_tris[i]); } - if (cache->cd_used & CD_MLOOPUV) { + if (cache->cd_used & CD_MASK_MLOOPUV) { DRW_vbo_request(cache->surf_per_mat[i], &cache->ordered.loop_uv); } - if (cache->cd_used & CD_TANGENT) { + if (cache->cd_used & CD_MASK_TANGENT) { DRW_vbo_request(cache->surf_per_mat[i], &cache->ordered.loop_tan); } DRW_vbo_request(cache->surf_per_mat[i], &cache->ordered.loop_pos_nor); diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index d90d7d36ebc..e17ec4f707e 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -1314,15 +1314,15 @@ void DRW_draw_callbacks_post_scene(void) /* annotations - temporary drawing buffer (3d space) */ /* XXX: Or should we use a proper draw/overlay engine for this case? */ if (do_annotations) { - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); /* XXX: as scene->gpd is not copied for COW yet */ ED_annotation_draw_view3d(DEG_get_input_scene(depsgraph), depsgraph, v3d, region, true); - GPU_depth_test(true); + GPU_depth_test(GPU_DEPTH_LESS_EQUAL); } drw_debug_draw(); - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); ED_region_draw_cb_draw(DST.draw_ctx.evil_C, DST.draw_ctx.region, REGION_DRAW_POST_VIEW); /* Callback can be nasty and do whatever they want with the state. @@ -1331,11 +1331,11 @@ void DRW_draw_callbacks_post_scene(void) /* needed so gizmo isn't obscured */ if ((v3d->gizmo_flag & V3D_GIZMO_HIDE) == 0) { - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); DRW_draw_gizmo_3d(); } - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); drw_engines_draw_text(); DRW_draw_region_info(); @@ -1343,7 +1343,7 @@ void DRW_draw_callbacks_post_scene(void) /* annotations - temporary drawing buffer (screenspace) */ /* XXX: Or should we use a proper draw/overlay engine for this case? */ if (((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) && (do_annotations)) { - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); /* XXX: as scene->gpd is not copied for COW yet */ ED_annotation_draw_view3d(DEG_get_input_scene(depsgraph), depsgraph, v3d, region, false); } @@ -1351,18 +1351,18 @@ void DRW_draw_callbacks_post_scene(void) if ((v3d->gizmo_flag & V3D_GIZMO_HIDE) == 0) { /* Draw 2D after region info so we can draw on top of the camera passepartout overlay. * 'DRW_draw_region_info' sets the projection in pixel-space. */ - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); DRW_draw_gizmo_2d(); } if (G.debug_value > 20 && G.debug_value < 30) { - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); /* local coordinate visible rect inside region, to accommodate overlapping ui */ const rcti *rect = ED_region_visible_rect(DST.draw_ctx.region); DRW_stats_draw(rect); } - GPU_depth_test(true); + GPU_depth_test(GPU_DEPTH_LESS_EQUAL); } } @@ -1703,7 +1703,7 @@ void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph GPU_viewport_free(DST.viewport); DRW_state_reset(); - glDisable(GL_DEPTH_TEST); + GPU_depth_test(GPU_DEPTH_NONE); /* Restore Drawing area. */ GPU_framebuffer_restore(); @@ -2438,7 +2438,7 @@ void DRW_draw_depth_object( GPU_framebuffer_bind(fbl->depth_only_fb); GPU_framebuffer_clear_depth(fbl->depth_only_fb, 1.0f); - GPU_depth_test(true); + GPU_depth_test(GPU_DEPTH_LESS_EQUAL); const float(*world_clip_planes)[4] = NULL; if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) { @@ -2485,7 +2485,7 @@ void DRW_draw_depth_object( } GPU_matrix_set(rv3d->viewmat); - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); GPU_framebuffer_restore(); DRW_opengl_context_disable(); } diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c index 47892b958d0..9902d3b0aeb 100644 --- a/source/blender/draw/intern/draw_manager_exec.c +++ b/source/blender/draw/intern/draw_manager_exec.c @@ -301,11 +301,8 @@ void DRW_state_reset(void) /* Should stay constant during the whole rendering. */ GPU_point_size(5); GPU_line_smooth(false); - /* Bypass U.pixelsize factor. */ - glLineWidth(1.0f); - - /* Reset blending function */ - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + /* Bypass U.pixelsize factor by using a factor of 0.0f. Will be clamped to 1.0f. */ + GPU_line_width(0.0f); } /** \} */ @@ -762,19 +759,14 @@ static void draw_call_resource_bind(DRWCommandsState *state, const DRWResourceHa /* Front face is not a resource but it is inside the resource handle. */ bool neg_scale = DRW_handle_negative_scale_get(handle); if (neg_scale != state->neg_scale) { - if (DST.view_active->is_inverted) { - glFrontFace(neg_scale ? GL_CCW : GL_CW); - } - else { - glFrontFace(neg_scale ? GL_CW : GL_CCW); - } state->neg_scale = neg_scale; + GPU_front_facing(neg_scale != DST.view_active->is_inverted); } int chunk = DRW_handle_chunk_get(handle); if (state->resource_chunk != chunk) { if (state->chunkid_loc != -1) { - GPU_shader_uniform_int(NULL, state->chunkid_loc, chunk); + GPU_shader_uniform_int(DST.shader, state->chunkid_loc, chunk); } if (state->obmats_loc != -1) { GPU_uniformbuffer_unbind(DST.vmempool->matrices_ubo[state->resource_chunk]); @@ -790,7 +782,7 @@ static void draw_call_resource_bind(DRWCommandsState *state, const DRWResourceHa if (state->resourceid_loc != -1) { int id = DRW_handle_id_get(handle); if (state->resource_id != id) { - GPU_shader_uniform_int(NULL, state->resourceid_loc, id); + GPU_shader_uniform_int(DST.shader, state->resourceid_loc, id); state->resource_id = id; } } @@ -898,7 +890,7 @@ static void draw_call_batching_finish(DRWShadingGroup *shgroup, DRWCommandsState /* Reset state */ if (state->neg_scale) { - glFrontFace(DST.view_active->is_inverted ? GL_CW : GL_CCW); + GPU_front_facing(DST.view_active->is_inverted); } if (state->obmats_loc != -1) { GPU_uniformbuffer_unbind(DST.vmempool->matrices_ubo[state->resource_chunk]); @@ -1110,7 +1102,7 @@ static void drw_draw_pass_ex(DRWPass *pass, drw_state_validate(); if (DST.view_active->is_inverted) { - glFrontFace(GL_CW); + GPU_front_facing(true); } DRW_stats_query_start(pass->name); @@ -1147,7 +1139,7 @@ static void drw_draw_pass_ex(DRWPass *pass, /* Reset default. */ if (DST.view_active->is_inverted) { - glFrontFace(GL_CCW); + GPU_front_facing(false); } DRW_stats_query_end(); diff --git a/source/blender/draw/intern/draw_view.c b/source/blender/draw/intern/draw_view.c index 0dc35d44788..d01e1a51080 100644 --- a/source/blender/draw/intern/draw_view.c +++ b/source/blender/draw/intern/draw_view.c @@ -105,7 +105,7 @@ void DRW_draw_cursor(void) GPU_color_mask(true, true, true, true); GPU_depth_mask(false); - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); if (is_cursor_visible(draw_ctx, scene, view_layer)) { int co[2]; diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c index 2dac273501d..889041daacf 100644 --- a/source/blender/editors/curve/editcurve_paint.c +++ b/source/blender/editors/curve/editcurve_paint.c @@ -419,7 +419,7 @@ static void curve_draw_stroke_3d(const struct bContext *UNUSED(C), uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); GPU_blend(GPU_BLEND_ALPHA); GPU_line_smooth(true); GPU_line_width(3.0f); @@ -441,7 +441,7 @@ static void curve_draw_stroke_3d(const struct bContext *UNUSED(C), immEnd(); /* Reset defaults */ - GPU_depth_test(true); + GPU_depth_test(GPU_DEPTH_LESS_EQUAL); GPU_blend(GPU_BLEND_NONE); GPU_line_smooth(false); diff --git a/source/blender/editors/gizmo_library/gizmo_draw_utils.c b/source/blender/editors/gizmo_library/gizmo_draw_utils.c index 033673a99a8..2896aa25930 100644 --- a/source/blender/editors/gizmo_library/gizmo_draw_utils.c +++ b/source/blender/editors/gizmo_library/gizmo_draw_utils.c @@ -84,13 +84,13 @@ void wm_gizmo_geometryinfo_draw(const GizmoGeomInfo *info, * since it causes issues leaving the GL state modified. */ #if 0 GPU_face_culling(GPU_CULL_BACK); - GPU_depth_test(true); + GPU_depth_test(GPU_DEPTH_LESS_EQUAL); #endif GPU_batch_draw(batch); #if 0 - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); GPU_face_culling(GPU_CULL_NONE); #endif diff --git a/source/blender/editors/gpencil/annotate_draw.c b/source/blender/editors/gpencil/annotate_draw.c index 654d1b87918..b6cbbe7712b 100644 --- a/source/blender/editors/gpencil/annotate_draw.c +++ b/source/blender/editors/gpencil/annotate_draw.c @@ -556,7 +556,7 @@ static void annotation_draw_strokes(const bGPDframe *gpf, const int no_xray = (dflag & GP_DRAWDATA_NO_XRAY); if (no_xray) { - GPU_depth_test(true); + GPU_depth_test(GPU_DEPTH_LESS_EQUAL); /* first arg is normally rv3d->dist, but this isn't * available here and seems to work quite well without */ @@ -574,7 +574,7 @@ static void annotation_draw_strokes(const bGPDframe *gpf, } if (no_xray) { - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); GPU_polygon_offset(0.0f, 0.0f); } diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c index 9d11c1c2a25..93767127cc7 100644 --- a/source/blender/editors/gpencil/drawgpencil.c +++ b/source/blender/editors/gpencil/drawgpencil.c @@ -348,7 +348,7 @@ static void gpencil_draw_strokes(tGPDdraw *tgpw) const int no_xray = (tgpw->dflag & GP_DRAWDATA_NO_XRAY); if (no_xray) { - GPU_depth_test(true); + GPU_depth_test(GPU_DEPTH_LESS_EQUAL); /* first arg is normally rv3d->dist, but this isn't * available here and seems to work quite well without */ @@ -393,7 +393,7 @@ static void gpencil_draw_strokes(tGPDdraw *tgpw) } } if (no_xray) { - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); GPU_polygon_offset(0.0f, 0.0f); } diff --git a/source/blender/editors/include/ED_buttons.h b/source/blender/editors/include/ED_buttons.h index ccef62eb8d2..8dafd10f774 100644 --- a/source/blender/editors/include/ED_buttons.h +++ b/source/blender/editors/include/ED_buttons.h @@ -26,8 +26,11 @@ extern "C" { #endif +struct bContext; struct SpaceProperties; +void ED_buttons_set_context(const struct bContext *C, PointerRNA *ptr, const short context); + int ED_buttons_tabs_list(struct SpaceProperties *sbuts, int *context_tabs_array); #ifdef __cplusplus diff --git a/source/blender/editors/include/ED_info.h b/source/blender/editors/include/ED_info.h index df6b6a20ddc..e3ce494e09a 100644 --- a/source/blender/editors/include/ED_info.h +++ b/source/blender/editors/include/ED_info.h @@ -31,8 +31,13 @@ struct Main; /* info_stats.c */ void ED_info_stats_clear(struct ViewLayer *view_layer); const char *ED_info_statusbar_string(struct Main *bmain, - struct bScreen *screen, - struct bContext *C); + struct Scene *scene, + struct ViewLayer *view_layer); + +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); diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index 4c7dd4fe66c..300ce2fd12c 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -329,6 +329,11 @@ void ED_object_constraint_dependency_tag_update(struct Main *bmain, struct Object *ob, struct bConstraint *con); +bool ED_object_constraint_move_to_index(struct ReportList *reports, + struct Object *ob, + struct bConstraint *con, + const int index); + /* object_modes.c */ bool ED_object_mode_compat_test(const struct Object *ob, eObjectMode mode); bool ED_object_mode_compat_set(struct bContext *C, diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index ad46dada0c9..dd7ca5c65a4 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -81,18 +81,12 @@ void ED_region_tag_refresh_ui(struct ARegion *region); void ED_region_tag_redraw_editor_overlays(struct ARegion *region); void ED_region_panels_init(struct wmWindowManager *wm, struct ARegion *region); -void ED_region_panels_ex(const struct bContext *C, - struct ARegion *region, - const char *contexts[], - int contextnr, - const bool vertical); +void ED_region_panels_ex(const struct bContext *C, struct ARegion *region, const char *contexts[]); void ED_region_panels(const struct bContext *C, struct ARegion *region); void ED_region_panels_layout_ex(const struct bContext *C, struct ARegion *region, struct ListBase *paneltypes, const char *contexts[], - int contextnr, - const bool vertical, const char *category_override); void ED_region_panels_layout(const struct bContext *C, struct ARegion *region); diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index f942ca8bafa..56c93e24182 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -1667,19 +1667,13 @@ void UI_panels_end(const struct bContext *C, struct ARegion *region, int *r_x, i void UI_panels_draw(const struct bContext *C, struct ARegion *region); struct Panel *UI_panel_find_by_type(struct ListBase *lb, struct PanelType *pt); -struct Panel *UI_panel_begin(struct ScrArea *area, - struct ARegion *region, +struct Panel *UI_panel_begin(struct ARegion *region, struct ListBase *lb, uiBlock *block, struct PanelType *pt, struct Panel *panel, bool *r_open); -void UI_panel_end(const struct ScrArea *area, - const struct ARegion *region, - uiBlock *block, - int width, - int height, - bool open); +void UI_panel_end(const struct ARegion *region, uiBlock *block, int width, int height, bool open); void UI_panels_scale(struct ARegion *region, float new_width); void UI_panel_label_offset(struct uiBlock *block, int *r_x, int *r_y); diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index a70bcd208ab..4982a27316c 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -134,43 +134,6 @@ static void panel_title_color_get(bool show_background, uchar color[4]) } } -/*********************** space specific code ************************/ -/* temporary code to remove all sbuts stuff from panel code */ - -/* SpaceProperties.align */ -typedef enum eSpaceButtons_Align { - BUT_HORIZONTAL = 0, - BUT_VERTICAL = 1, - BUT_AUTO = 2, -} eSpaceButtons_Align; - -static int panel_aligned(const ScrArea *area, const ARegion *region) -{ - if (area->spacetype == SPACE_PROPERTIES && region->regiontype == RGN_TYPE_WINDOW) { - return BUT_VERTICAL; - } - if (area->spacetype == SPACE_USERPREF && region->regiontype == RGN_TYPE_WINDOW) { - return BUT_VERTICAL; - } - if (area->spacetype == SPACE_FILE && region->regiontype == RGN_TYPE_CHANNELS) { - return BUT_VERTICAL; - } - if (area->spacetype == SPACE_IMAGE && region->regiontype == RGN_TYPE_PREVIEW) { - return BUT_VERTICAL; - } - if (ELEM(region->regiontype, - RGN_TYPE_UI, - RGN_TYPE_TOOLS, - RGN_TYPE_TOOL_PROPS, - RGN_TYPE_HUD, - RGN_TYPE_NAV_BAR, - RGN_TYPE_EXECUTE)) { - return BUT_VERTICAL; - } - - return 0; -} - static bool panel_active_animation_changed(ListBase *lb, Panel **pa_animation, bool *no_animation) { LISTBASE_FOREACH (Panel *, panel, lb) { @@ -530,13 +493,9 @@ static void reorder_instanced_panel_list(bContext *C, ARegion *region, Panel *dr static bool panel_set_expand_from_list_data_recursive(Panel *panel, short flag, short *flag_index) { bool open = (flag & (1 << *flag_index)); - bool changed = (open == (bool)(panel->flag & PNL_CLOSEDY)); - if (open) { - panel->flag &= ~PNL_CLOSEDY; - } - else { - panel->flag |= PNL_CLOSEDY; - } + bool changed = (open == (bool)(panel->flag & PNL_CLOSED)); + SET_FLAG_FROM_TEST(panel->flag, !open, PNL_CLOSED); + LISTBASE_FOREACH (Panel *, child, &panel->children) { *flag_index = *flag_index + 1; changed |= panel_set_expand_from_list_data_recursive(child, flag, flag_index); @@ -572,13 +531,9 @@ void UI_panel_set_expand_from_list_data(const bContext *C, Panel *panel) */ static void get_panel_expand_flag(Panel *panel, short *flag, short *flag_index) { - bool open = !(panel->flag & PNL_CLOSEDY); - if (open) { - *flag |= (1 << *flag_index); - } - else { - *flag &= ~(1 << *flag_index); - } + bool open = !(panel->flag & PNL_CLOSED); + SET_FLAG_FROM_TEST(*flag, open, (1 << *flag_index)); + LISTBASE_FOREACH (Panel *, child, &panel->children) { *flag_index = *flag_index + 1; get_panel_expand_flag(child, flag, flag_index); @@ -635,14 +590,10 @@ static bool panel_set_flag_recursive(Panel *panel, int flag, bool value) return changed; } -static void panels_collapse_all(const bContext *C, - ScrArea *area, - ARegion *region, - const Panel *from_panel) +static void panels_collapse_all(const bContext *C, ARegion *region, const Panel *from_panel) { const bool has_category_tabs = UI_panel_category_is_visible(region); const char *category = has_category_tabs ? UI_panel_category_active_get(region, false) : NULL; - const int flag = ((panel_aligned(area, region) == BUT_HORIZONTAL) ? PNL_CLOSEDX : PNL_CLOSEDY); const PanelType *from_pt = from_panel->type; LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { @@ -654,7 +605,6 @@ static void panels_collapse_all(const bContext *C, if ((panel->flag & PNL_PIN) || !category || !pt->category[0] || STREQ(pt->category, category)) { panel->flag &= ~PNL_CLOSED; - panel->flag |= flag; } } } @@ -692,19 +642,13 @@ Panel *UI_panel_find_by_type(ListBase *lb, PanelType *pt) /** * \note \a panel should be return value from #UI_panel_find_by_type and can be NULL. */ -Panel *UI_panel_begin(ScrArea *area, - ARegion *region, - ListBase *lb, - uiBlock *block, - PanelType *pt, - Panel *panel, - bool *r_open) +Panel *UI_panel_begin( + ARegion *region, ListBase *lb, uiBlock *block, PanelType *pt, Panel *panel, bool *r_open) { Panel *panel_last; const char *drawname = CTX_IFACE_(pt->translation_context, pt->label); const char *idname = pt->idname; const bool newpanel = (panel == NULL); - int align = panel_aligned(area, region); if (!newpanel) { panel->type = pt; @@ -716,12 +660,7 @@ Panel *UI_panel_begin(ScrArea *area, BLI_strncpy(panel->panelname, idname, sizeof(panel->panelname)); if (pt->flag & PNL_DEFAULT_CLOSED) { - if (align == BUT_VERTICAL) { - panel->flag |= PNL_CLOSEDY; - } - else { - panel->flag |= PNL_CLOSEDX; - } + panel->flag |= PNL_CLOSED; } panel->ofsx = 0; @@ -790,11 +729,10 @@ Panel *UI_panel_begin(ScrArea *area, return panel; } -static float panel_region_offset_x_get(const ARegion *region, int align) +static float panel_region_offset_x_get(const ARegion *region) { if (UI_panel_category_is_visible(region)) { - if (align == BUT_VERTICAL && - (RGN_ALIGN_ENUM_FROM_MASK(region->alignment) != RGN_ALIGN_RIGHT)) { + if (RGN_ALIGN_ENUM_FROM_MASK(region->alignment) != RGN_ALIGN_RIGHT) { return UI_PANEL_CATEGORY_MARGIN_WIDTH; } } @@ -802,8 +740,7 @@ static float panel_region_offset_x_get(const ARegion *region, int align) return 0; } -void UI_panel_end( - const ScrArea *area, const ARegion *region, uiBlock *block, int width, int height, bool open) +void UI_panel_end(const ARegion *region, uiBlock *block, int width, int height, bool open) { Panel *panel = block->panel; @@ -843,8 +780,7 @@ void UI_panel_end( panel->ofsy += old_sizey - panel->sizey; } - int align = panel_aligned(area, region); - panel->runtime.region_ofsx = panel_region_offset_x_get(region, align); + panel->runtime.region_ofsx = panel_region_offset_x_get(region); if (old_region_ofsx != panel->runtime.region_ofsx) { panel->runtime_flag |= PNL_ANIM_ALIGN; } @@ -955,8 +891,6 @@ void ui_draw_aligned_panel(uiStyle *style, Panel *panel = block->panel; rctf itemrect; float color[4]; - const bool is_closed_x = (panel->flag & PNL_CLOSEDX) ? true : false; - const bool is_closed_y = (panel->flag & PNL_CLOSEDY) ? true : false; const bool is_subpanel = (panel->type && panel->type->parent); const bool show_drag = (!is_subpanel && /* FIXME(campbell): currently no background means floating panel which @@ -993,12 +927,12 @@ void ui_draw_aligned_panel(uiStyle *style, /* Expand the top a tiny bit to give header buttons equal size above and below. */ rcti box_rect = {rect->xmin, rect->xmax, - (is_closed_x || is_closed_y) ? headrect.ymin : rect->ymin, + (panel->flag & PNL_CLOSED) ? headrect.ymin : rect->ymin, headrect.ymax + U.pixelsize}; ui_draw_box_opaque(&box_rect, UI_CNR_ALL); /* Mimick the border between aligned box widgets for the bottom of the header. */ - if (!(is_closed_x || is_closed_y)) { + if (!(panel->flag & PNL_CLOSED)) { immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); GPU_blend(GPU_BLEND_ALPHA); @@ -1021,7 +955,6 @@ void ui_draw_aligned_panel(uiStyle *style, /* Draw the header backdrop. */ if (show_background && !is_subpanel && !draw_box_style) { float minx = rect->xmin; - float maxx = is_closed_x ? (minx + PNL_HEADER / block->aspect) : rect->xmax; float y = headrect.ymax; immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); @@ -1029,15 +962,15 @@ void ui_draw_aligned_panel(uiStyle *style, /* draw with background color */ immUniformThemeColor(TH_PANEL_HEADER); - immRectf(pos, minx, headrect.ymin, maxx, y); + immRectf(pos, minx, headrect.ymin, rect->xmax, y); immBegin(GPU_PRIM_LINES, 4); immVertex2f(pos, minx, y); - immVertex2f(pos, maxx, y); + immVertex2f(pos, rect->xmax, y); immVertex2f(pos, minx, y); - immVertex2f(pos, maxx, y); + immVertex2f(pos, rect->xmax, y); immEnd(); @@ -1072,45 +1005,34 @@ void ui_draw_aligned_panel(uiStyle *style, if (is_subpanel) { titlerect.xmin += (0.7f * UI_UNIT_X) / block->aspect + 0.001f; } - if (is_closed_x == false) { - ui_draw_aligned_panel_header(style, block, &titlerect, 'h', show_background); + ui_draw_aligned_panel_header(style, block, &titlerect, 'h', show_background); - if (show_drag) { - /* itemrect smaller */ - const float scale = 0.7; - itemrect.xmax = headrect.xmax - (0.2f * UI_UNIT_X); - itemrect.xmin = itemrect.xmax - BLI_rcti_size_y(&headrect); - itemrect.ymin = headrect.ymin; - itemrect.ymax = headrect.ymax; - BLI_rctf_scale(&itemrect, scale); + if (show_drag) { + /* itemrect smaller */ + const float scale = 0.7; + itemrect.xmax = headrect.xmax - (0.2f * UI_UNIT_X); + itemrect.xmin = itemrect.xmax - BLI_rcti_size_y(&headrect); + itemrect.ymin = headrect.ymin; + itemrect.ymax = headrect.ymax; + BLI_rctf_scale(&itemrect, scale); - GPU_matrix_push(); - GPU_matrix_translate_2f(itemrect.xmin, itemrect.ymin); + GPU_matrix_push(); + GPU_matrix_translate_2f(itemrect.xmin, itemrect.ymin); - const int col_tint = 84; - float col_high[4], col_dark[4]; - UI_GetThemeColorShade4fv(TH_PANEL_HEADER, col_tint, col_high); - UI_GetThemeColorShade4fv(TH_PANEL_BACK, -col_tint, col_dark); + const int col_tint = 84; + float col_high[4], col_dark[4]; + UI_GetThemeColorShade4fv(TH_PANEL_HEADER, col_tint, col_high); + UI_GetThemeColorShade4fv(TH_PANEL_BACK, -col_tint, col_dark); - GPUBatch *batch = GPU_batch_preset_panel_drag_widget( - U.pixelsize, col_high, col_dark, BLI_rcti_size_y(&headrect) * scale); - GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_FLAT_COLOR); - GPU_batch_draw(batch); - GPU_matrix_pop(); - } + GPUBatch *batch = GPU_batch_preset_panel_drag_widget( + U.pixelsize, col_high, col_dark, BLI_rcti_size_y(&headrect) * scale); + GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_FLAT_COLOR); + GPU_batch_draw(batch); + GPU_matrix_pop(); } /* Draw panel backdrop. */ - if (is_closed_y) { - /* skip */ - } - else if (is_closed_x) { - /* draw vertical title */ - ui_draw_aligned_panel_header(style, block, &headrect, 'v', show_background); - pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - } - /* an open panel */ - else { + if (!(panel->flag & PNL_CLOSED)) { /* in some occasions, draw a border */ if (panel->flag & PNL_SELECT && !is_subpanel) { float radius; @@ -1186,10 +1108,7 @@ void ui_draw_aligned_panel(uiStyle *style, rgb_uchar_to_float(tria_color, col_title); tria_color[3] = 1.0f; - if (is_closed_y) { - ui_draw_anti_tria_rect(&itemrect, 'h', tria_color); - } - else if (is_closed_x) { + if (panel->flag & PNL_CLOSED) { ui_draw_anti_tria_rect(&itemrect, 'h', tria_color); } else { @@ -1200,15 +1119,6 @@ void ui_draw_aligned_panel(uiStyle *style, /************************** panel alignment *************************/ -static int get_panel_header(const Panel *panel) -{ - if (panel->type && (panel->type->flag & PNL_NO_HEADER)) { - return 0; - } - - return PNL_HEADER; -} - static int get_panel_size_y(const Panel *panel) { if (panel->type && (panel->type->flag & PNL_NO_HEADER)) { @@ -1238,20 +1148,12 @@ int UI_panel_size_y(const Panel *panel) * change sizey or location when closed */ static int get_panel_real_ofsy(Panel *panel) { - if (panel->flag & PNL_CLOSEDY) { + if (panel->flag & PNL_CLOSED) { return panel->ofsy + panel->sizey; } return panel->ofsy; } -static int get_panel_real_ofsx(Panel *panel) -{ - if (panel->flag & PNL_CLOSEDX) { - return panel->ofsx + get_panel_header(panel); - } - return panel->ofsx + panel->sizex; -} - bool UI_panel_is_dragging(const struct Panel *panel) { uiHandlePanelData *data = panel->activedata; @@ -1270,26 +1172,6 @@ bool UI_panel_is_dragging(const struct Panel *panel) * panels do not match for sorting */ -static int find_leftmost_panel(const void *a1, const void *a2) -{ - const PanelSort *ps1 = a1, *ps2 = a2; - - if (ps1->panel->ofsx > ps2->panel->ofsx) { - return 1; - } - if (ps1->panel->ofsx < ps2->panel->ofsx) { - return -1; - } - if (ps1->panel->sortorder > ps2->panel->sortorder) { - return 1; - } - if (ps1->panel->sortorder < ps2->panel->sortorder) { - return -1; - } - - return 0; -} - static int find_highest_panel(const void *a1, const void *a2) { const PanelSort *ps1 = a1, *ps2 = a2; @@ -1356,12 +1238,11 @@ static void align_sub_panels(Panel *panel) /* this doesn't draw */ /* returns 1 when it did something */ -static bool uiAlignPanelStep(ScrArea *area, ARegion *region, const float fac, const bool drag) +static bool uiAlignPanelStep(ARegion *region, const float fac, const bool drag) { PanelSort *ps, *panelsort, *psnext; int a, tot = 0; bool done; - int align = panel_aligned(area, region); /* count active, not tabbed panels */ LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { @@ -1374,18 +1255,6 @@ static bool uiAlignPanelStep(ScrArea *area, ARegion *region, const float fac, co return 0; } - /* extra; change close direction? */ - LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { - if (panel->runtime_flag & PNL_ACTIVE) { - if ((panel->flag & PNL_CLOSEDX) && (align == BUT_VERTICAL)) { - panel->flag ^= PNL_CLOSED; - } - else if ((panel->flag & PNL_CLOSEDY) && (align == BUT_HORIZONTAL)) { - panel->flag ^= PNL_CLOSED; - } - } - } - /* sort panels */ panelsort = MEM_callocN(tot * sizeof(PanelSort), "panelsort"); @@ -1400,12 +1269,7 @@ static bool uiAlignPanelStep(ScrArea *area, ARegion *region, const float fac, co if (drag) { /* while we are dragging, we sort on location and update sortorder */ - if (align == BUT_VERTICAL) { - qsort(panelsort, tot, sizeof(PanelSort), find_highest_panel); - } - else { - qsort(panelsort, tot, sizeof(PanelSort), find_leftmost_panel); - } + qsort(panelsort, tot, sizeof(PanelSort), find_highest_panel); for (ps = panelsort, a = 0; a < tot; a++, ps++) { ps->orig->sortorder = a; @@ -1418,7 +1282,7 @@ static bool uiAlignPanelStep(ScrArea *area, ARegion *region, const float fac, co /* no smart other default start loc! this keeps switching f5/f6/etc compatible */ ps = panelsort; - ps->panel->runtime.region_ofsx = panel_region_offset_x_get(region, align); + ps->panel->runtime.region_ofsx = panel_region_offset_x_get(region); ps->panel->ofsx = 0; ps->panel->ofsy = -get_panel_size_y(ps->panel); ps->panel->ofsx += ps->panel->runtime.region_ofsx; @@ -1426,22 +1290,15 @@ static bool uiAlignPanelStep(ScrArea *area, ARegion *region, const float fac, co for (a = 0; a < tot - 1; a++, ps++) { psnext = ps + 1; - if (align == BUT_VERTICAL) { - bool use_box = ps->panel->type && ps->panel->type->flag & PNL_DRAW_BOX; - bool use_box_next = psnext->panel->type && psnext->panel->type->flag & PNL_DRAW_BOX; - psnext->panel->ofsx = ps->panel->ofsx; - psnext->panel->ofsy = get_panel_real_ofsy(ps->panel) - get_panel_size_y(psnext->panel); + bool use_box = ps->panel->type && ps->panel->type->flag & PNL_DRAW_BOX; + bool use_box_next = psnext->panel->type && psnext->panel->type->flag & PNL_DRAW_BOX; + psnext->panel->ofsx = ps->panel->ofsx; + psnext->panel->ofsy = get_panel_real_ofsy(ps->panel) - get_panel_size_y(psnext->panel); - /* Extra margin for box style panels. */ - ps->panel->ofsx += (use_box) ? UI_PANEL_BOX_STYLE_MARGIN : 0.0f; - if (use_box || use_box_next) { - psnext->panel->ofsy -= UI_PANEL_BOX_STYLE_MARGIN; - } - } - else { - psnext->panel->ofsx = get_panel_real_ofsx(ps->panel); - psnext->panel->ofsy = ps->panel->ofsy + get_panel_size_y(ps->panel) - - get_panel_size_y(psnext->panel); + /* Extra margin for box style panels. */ + ps->panel->ofsx += (use_box) ? UI_PANEL_BOX_STYLE_MARGIN : 0.0f; + if (use_box || use_box_next) { + psnext->panel->ofsy -= UI_PANEL_BOX_STYLE_MARGIN; } } /* Extra margin for the last panel if it's a box-style panel. */ @@ -1482,25 +1339,16 @@ static bool uiAlignPanelStep(ScrArea *area, ARegion *region, const float fac, co return done; } -static void ui_panels_size(ScrArea *area, ARegion *region, int *r_x, int *r_y) +static void ui_panels_size(ARegion *region, int *r_x, int *r_y) { - int align = panel_aligned(area, region); int sizex = 0; int sizey = 0; /* compute size taken up by panels, for setting in view2d */ LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { if (panel->runtime_flag & PNL_ACTIVE) { - int pa_sizex, pa_sizey; - - if (align == BUT_VERTICAL) { - pa_sizex = panel->ofsx + panel->sizex; - pa_sizey = get_panel_real_ofsy(panel); - } - else { - pa_sizex = get_panel_real_ofsx(panel) + panel->sizex; - pa_sizey = panel->ofsy + get_panel_size_y(panel); - } + int pa_sizex = panel->ofsx + panel->sizex; + int pa_sizey = get_panel_real_ofsy(panel); sizex = max_ii(sizex, pa_sizex); sizey = min_ii(sizey, pa_sizey); @@ -1521,7 +1369,6 @@ static void ui_panels_size(ScrArea *area, ARegion *region, int *r_x, int *r_y) static void ui_do_animate(bContext *C, Panel *panel) { uiHandlePanelData *data = panel->activedata; - ScrArea *area = CTX_wm_area(C); ARegion *region = CTX_wm_region(C); float fac; @@ -1529,7 +1376,7 @@ static void ui_do_animate(bContext *C, Panel *panel) fac = min_ff(sqrtf(fac), 1.0f); /* for max 1 second, interpolate positions */ - if (uiAlignPanelStep(area, region, fac, false)) { + if (uiAlignPanelStep(region, fac, false)) { ED_region_tag_redraw(region); } else { @@ -1590,7 +1437,7 @@ void UI_panels_end(const bContext *C, ARegion *region, int *r_x, int *r_y) panel_activate_state(C, panel, PANEL_STATE_ANIMATION); } else { - uiAlignPanelStep(area, region, 1.0, false); + uiAlignPanelStep(region, 1.0, false); } } @@ -1609,7 +1456,7 @@ void UI_panels_end(const bContext *C, ARegion *region, int *r_x, int *r_y) } /* compute size taken up by panel */ - ui_panels_size(area, region, r_x, r_y); + ui_panels_size(region, r_x, r_y); } void UI_panels_draw(const bContext *C, ARegion *region) @@ -1655,9 +1502,7 @@ void UI_panels_scale(ARegion *region, float new_width) static void ui_do_drag(const bContext *C, const wmEvent *event, Panel *panel) { uiHandlePanelData *data = panel->activedata; - ScrArea *area = CTX_wm_area(C); ARegion *region = CTX_wm_region(C); - short align = panel_aligned(area, region); /* Keep the drag position in the region with a small pad to keep the panel visible. */ int x = clamp_i(event->x, region->winrct.xmin, region->winrct.xmax + DRAG_REGION_PAD); @@ -1690,9 +1535,7 @@ static void ui_do_drag(const bContext *C, const wmEvent *event, Panel *panel) panel->ofsx = data->startofsx + round_fl_to_int(dx); panel->ofsy = data->startofsy + round_fl_to_int(dy); - if (align) { - uiAlignPanelStep(area, region, 0.2f, true); - } + uiAlignPanelStep(region, 0.2f, true); } ED_region_tag_redraw(region); @@ -1706,27 +1549,20 @@ static uiPanelMouseState ui_panel_mouse_state_get(const uiBlock *block, const int mx, const int my) { - /* open panel */ - if (panel->flag & PNL_CLOSEDX) { - if ((block->rect.xmin <= mx) && (block->rect.xmin + PNL_HEADER >= mx)) { - return PANEL_MOUSE_INSIDE_HEADER; - } - } - /* outside left/right side */ - else if ((block->rect.xmin > mx) || (block->rect.xmax < mx)) { - /* pass */ + if (!IN_RANGE((float)mx, block->rect.xmin, block->rect.xmax)) { + return PANEL_MOUSE_OUTSIDE; } - else if ((block->rect.ymax <= my) && (block->rect.ymax + PNL_HEADER >= my)) { + + if (IN_RANGE((float)my, block->rect.ymax, block->rect.ymax + PNL_HEADER)) { return PANEL_MOUSE_INSIDE_HEADER; } - /* open panel */ - else if (!(panel->flag & PNL_CLOSEDY)) { - if ((block->rect.xmin <= mx) && (block->rect.xmax >= mx)) { - if ((block->rect.ymin <= my) && (block->rect.ymax + PNL_HEADER >= my)) { - return PANEL_MOUSE_INSIDE_CONTENT; - } + + if (!(panel->flag & PNL_CLOSED)) { + if (IN_RANGE((float)my, block->rect.ymin, block->rect.ymax + PNL_HEADER)) { + return PANEL_MOUSE_INSIDE_CONTENT; } } + return PANEL_MOUSE_OUTSIDE; } @@ -1745,7 +1581,6 @@ static void ui_panel_drag_collapse(bContext *C, uiPanelDragCollapseHandle *dragcol_data, const int xy_dst[2]) { - ScrArea *area = CTX_wm_area(C); ARegion *region = CTX_wm_region(C); Panel *panel; @@ -1754,20 +1589,14 @@ static void ui_panel_drag_collapse(bContext *C, float xy_b_block[2] = {UNPACK2(xy_dst)}; rctf rect = block->rect; int oldflag; - const bool is_horizontal = (panel_aligned(area, region) == BUT_HORIZONTAL); if ((panel = block->panel) == 0 || (panel->type && (panel->type->flag & PNL_NO_HEADER))) { continue; } oldflag = panel->flag; - /* lock one axis */ - if (is_horizontal) { - xy_b_block[1] = dragcol_data->xy_init[1]; - } - else { - xy_b_block[0] = dragcol_data->xy_init[0]; - } + /* lock axis */ + xy_b_block[0] = dragcol_data->xy_init[0]; /* use cursor coords in block space */ ui_window_to_block_fl(region, block, &xy_a_block[0], &xy_a_block[1]); @@ -1776,20 +1605,11 @@ static void ui_panel_drag_collapse(bContext *C, /* set up rect to match header size */ rect.ymin = rect.ymax; rect.ymax = rect.ymin + PNL_HEADER; - if (panel->flag & PNL_CLOSEDX) { - rect.xmax = rect.xmin + PNL_HEADER; - } /* touch all panels between last mouse coord and the current one */ if (BLI_rctf_isect_segment(&rect, xy_a_block, xy_b_block)) { - /* force panel to close */ - if (dragcol_data->was_first_open == true) { - panel->flag |= (is_horizontal ? PNL_CLOSEDX : PNL_CLOSEDY); - } - /* force panel to open */ - else { - panel->flag &= ~PNL_CLOSED; - } + /* Force panel to open or close. */ + SET_FLAG_FROM_TEST(panel->flag, dragcol_data->was_first_open, PNL_CLOSED); /* if panel->flag has changed this means a panel was opened/closed here */ if (panel->flag != oldflag) { @@ -1856,9 +1676,8 @@ static void ui_panel_drag_collapse_handler_add(const bContext *C, const bool was /* this function is supposed to call general window drawing too */ /* also it supposes a block has panel, and isn't a menu */ static void ui_handle_panel_header( - const bContext *C, uiBlock *block, int mx, int my, int event, short ctrl, short shift) + const bContext *C, uiBlock *block, int mx, int event, short ctrl, short shift) { - ScrArea *area = CTX_wm_area(C); ARegion *region = CTX_wm_region(C); #ifdef USE_PIN_HIDDEN const bool show_pin = UI_panel_category_is_visible(region) && @@ -1870,7 +1689,7 @@ static void ui_handle_panel_header( const bool is_subpanel = (block->panel->type && block->panel->type->parent); const bool show_drag = !is_subpanel; - int align = panel_aligned(area, region), button = 0; + int button = 0; rctf rect_drag, rect_pin; float rect_leftmost; @@ -1901,11 +1720,6 @@ static void ui_handle_panel_header( button = 2; } } - else if (block->panel->flag & PNL_CLOSEDX) { - if (my >= block->rect.ymax) { - button = 1; - } - } else if (mx < rect_leftmost) { button = 1; } @@ -1921,20 +1735,18 @@ static void ui_handle_panel_header( /* For parent panels, collapse all other panels or toggle children. */ if (block->panel->type != NULL && block->panel->type->parent == NULL) { if (block->panel->flag & PNL_CLOSED || BLI_listbase_is_empty(&block->panel->children)) { - panels_collapse_all(C, area, region, block->panel); + panels_collapse_all(C, region, block->panel); /* Reset the view - we don't want to display a view without content. */ UI_view2d_offset(®ion->v2d, 0.0f, 1.0f); } else { - const int closed_flag = (align == BUT_HORIZONTAL) ? PNL_CLOSEDX : PNL_CLOSEDY; /* If a panel has sub-panels and it's open, toggle the expansion * of the sub-panels (based on the expansion of the first subpanel). */ Panel *first_child = block->panel->children.first; BLI_assert(first_child != NULL); - panel_set_flag_recursive( - block->panel, closed_flag, (first_child->flag & PNL_CLOSED) == 0); - block->panel->flag |= closed_flag; + panel_set_flag_recursive(block->panel, PNL_CLOSED, !(first_child->flag & PNL_CLOSED)); + block->panel->flag |= PNL_CLOSED; } } } @@ -1950,16 +1762,9 @@ static void ui_handle_panel_header( ui_panel_drag_collapse_handler_add(C, false); } } - else if (align == BUT_HORIZONTAL) { - block->panel->flag |= PNL_CLOSEDX; - - if (event == LEFTMOUSE) { - ui_panel_drag_collapse_handler_add(C, true); - } - } else { /* snap down to bottom screen edge */ - block->panel->flag |= PNL_CLOSEDY; + block->panel->flag |= PNL_CLOSED; if (block->panel->snap & PNL_SNAP_BOTTOM) { block->panel->ofsy = -block->panel->sizey; } @@ -1972,15 +1777,7 @@ static void ui_handle_panel_header( set_panels_list_data_expand_flag(C, region); } - if (align) { - panel_activate_state(C, block->panel, PANEL_STATE_ANIMATION); - } - else { - /* FIXME: this doesn't update the panel drawing, assert to avoid debugging why this is. - * We could fix this in the future if it's ever needed. */ - BLI_assert(0); - ED_region_tag_redraw(region); - } + panel_activate_state(C, block->panel, PANEL_STATE_ANIMATION); } else if (show_drag && BLI_rctf_isect_x(&rect_drag, mx)) { /* XXX, for now don't allow dragging in floating windows yet. */ @@ -2595,6 +2392,10 @@ int ui_handler_panel_region(bContext *C, retval = WM_UI_HANDLER_CONTINUE; + if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { + return retval; + } + /* Scrollbars can overlap panels now, they have handling priority. */ if (UI_view2d_mouse_in_scrollers(region, ®ion->v2d, event->x, event->y)) { return retval; @@ -2653,13 +2454,13 @@ int ui_handler_panel_region(bContext *C, if (event->type == EVT_AKEY && ((event->ctrl + event->oskey + event->shift + event->alt) == 0)) { - if (panel->flag & PNL_CLOSEDY) { + if (panel->flag & PNL_CLOSED) { if ((block->rect.ymax <= my) && (block->rect.ymax + PNL_HEADER >= my)) { - ui_handle_panel_header(C, block, mx, my, event->type, event->ctrl, event->shift); + ui_handle_panel_header(C, block, mx, event->type, event->ctrl, event->shift); } } else { - ui_handle_panel_header(C, block, mx, my, event->type, event->ctrl, event->shift); + ui_handle_panel_header(C, block, mx, event->type, event->ctrl, event->shift); } retval = WM_UI_HANDLER_BREAK; @@ -2679,7 +2480,7 @@ int ui_handler_panel_region(bContext *C, /* open close on header */ if (ELEM(event->type, EVT_RETKEY, EVT_PADENTER)) { if (mouse_state == PANEL_MOUSE_INSIDE_HEADER) { - ui_handle_panel_header(C, block, mx, my, EVT_RETKEY, event->ctrl, event->shift); + ui_handle_panel_header(C, block, mx, EVT_RETKEY, event->ctrl, event->shift); retval = WM_UI_HANDLER_BREAK; break; } @@ -2689,7 +2490,7 @@ int ui_handler_panel_region(bContext *C, retval = WM_UI_HANDLER_BREAK; if (mouse_state == PANEL_MOUSE_INSIDE_HEADER) { - ui_handle_panel_header(C, block, mx, my, event->type, event->ctrl, event->shift); + ui_handle_panel_header(C, block, mx, event->type, event->ctrl, event->shift); retval = WM_UI_HANDLER_BREAK; break; } @@ -2773,16 +2574,7 @@ static int ui_handler_panel(bContext *C, const wmEvent *event, void *userdata) /* verify if we can stop */ if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { - ScrArea *area = CTX_wm_area(C); - ARegion *region = CTX_wm_region(C); - int align = panel_aligned(area, region); - - if (align) { - panel_activate_state(C, panel, PANEL_STATE_ANIMATION); - } - else { - panel_activate_state(C, panel, PANEL_STATE_EXIT); - } + panel_activate_state(C, panel, PANEL_STATE_ANIMATION); } else if (event->type == MOUSEMOVE) { if (data->state == PANEL_STATE_DRAG) { diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 0de1d64dcfe..0e801c8cee2 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -7361,6 +7361,10 @@ int uiTemplateRecentFiles(uiLayout *layout, int rows) { int i; LISTBASE_FOREACH_INDEX (RecentFile *, recent, &G.recent_files, i) { + if (i >= rows) { + break; + } + const char *filename = BLI_path_basename(recent->filepath); PointerRNA ptr; uiItemFullO(layout, @@ -7373,10 +7377,6 @@ int uiTemplateRecentFiles(uiLayout *layout, int rows) &ptr); RNA_string_set(&ptr, "filepath", recent->filepath); RNA_boolean_set(&ptr, "display_file_selector", false); - - if (i > rows) { - break; - } } return i; diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index fa2f2b0d1b9..fca960336f1 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -1096,7 +1096,8 @@ static void widgetbase_outline(uiWidgetBase *wtb, uint pos) float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 because the last pair is wrapped */ widget_verts_to_triangle_strip(wtb, wtb->totvert, triangle_strip); - widget_draw_vertex_buffer(pos, 0, GL_TRIANGLE_STRIP, triangle_strip, NULL, wtb->totvert * 2 + 2); + widget_draw_vertex_buffer( + pos, 0, GPU_PRIM_TRI_STRIP, triangle_strip, NULL, wtb->totvert * 2 + 2); } static void widgetbase_set_uniform_alpha_discard(uiWidgetBase *wtb, @@ -2758,7 +2759,7 @@ static void widget_softshadow(const rcti *rect, int roundboxalign, const float r widget_verts_to_triangle_strip(&wtb, totvert, triangle_strip); - widget_draw_vertex_buffer(pos, 0, GL_TRIANGLE_STRIP, triangle_strip, NULL, totvert * 2); + widget_draw_vertex_buffer(pos, 0, GPU_PRIM_TRI_STRIP, triangle_strip, NULL, totvert * 2); } immUnbindProgram(); diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c index dbaa335a9bf..8acbb328ab0 100644 --- a/source/blender/editors/mask/mask_draw.c +++ b/source/blender/editors/mask/mask_draw.c @@ -750,7 +750,7 @@ void ED_mask_draw_region( IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR); GPU_shader_uniform_vector( state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, red); - immDrawPixelsTex(&state, 0.0f, 0.0f, width, height, GL_R16F, false, buffer, 1.0f, 1.0f, NULL); + immDrawPixelsTex(&state, 0.0f, 0.0f, width, height, GPU_R16F, false, buffer, 1.0f, 1.0f, NULL); GPU_matrix_pop(); diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index 94cd7650abe..6facee77c1e 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -1051,7 +1051,7 @@ static void knife_init_colors(KnifeColors *colors) static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), void *arg) { const KnifeTool_OpData *kcd = arg; - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); GPU_matrix_push_projection(); GPU_polygon_offset(1.0f, 1.0f); @@ -1222,7 +1222,7 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), v GPU_matrix_pop_projection(); /* Reset default */ - GPU_depth_test(true); + GPU_depth_test(GPU_DEPTH_LESS_EQUAL); } /** diff --git a/source/blender/editors/mesh/editmesh_preselect_edgering.c b/source/blender/editors/mesh/editmesh_preselect_edgering.c index d9bd63ef35f..aa1df3d76fc 100644 --- a/source/blender/editors/mesh/editmesh_preselect_edgering.c +++ b/source/blender/editors/mesh/editmesh_preselect_edgering.c @@ -159,7 +159,7 @@ void EDBM_preselect_edgering_draw(struct EditMesh_PreSelEdgeRing *psel, const fl return; } - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); GPU_matrix_push(); GPU_matrix_mul(matrix); @@ -197,7 +197,7 @@ void EDBM_preselect_edgering_draw(struct EditMesh_PreSelEdgeRing *psel, const fl GPU_matrix_pop(); /* Reset default */ - GPU_depth_test(true); + GPU_depth_test(GPU_DEPTH_LESS_EQUAL); } static void view3d_preselect_mesh_edgering_update_verts_from_edge( diff --git a/source/blender/editors/mesh/editmesh_preselect_elem.c b/source/blender/editors/mesh/editmesh_preselect_elem.c index d53a1e2b55c..dfd646c767f 100644 --- a/source/blender/editors/mesh/editmesh_preselect_elem.c +++ b/source/blender/editors/mesh/editmesh_preselect_elem.c @@ -133,7 +133,7 @@ void EDBM_preselect_elem_draw(struct EditMesh_PreSelElem *psel, const float matr return; } - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); GPU_matrix_push(); GPU_matrix_mul(matrix); @@ -204,7 +204,7 @@ void EDBM_preselect_elem_draw(struct EditMesh_PreSelElem *psel, const float matr GPU_matrix_pop(); /* Reset default */ - GPU_depth_test(true); + GPU_depth_test(GPU_DEPTH_LESS_EQUAL); } static void view3d_preselect_mesh_elem_update_from_vert(struct EditMesh_PreSelElem *psel, diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index 70404af6433..60838d08cc5 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -1421,6 +1421,24 @@ void ED_object_constraint_dependency_tag_update(Main *bmain, Object *ob, bConstr DEG_relations_tag_update(bmain); } +/* TODO (Nathan): Use the reports? */ +bool ED_object_constraint_move_to_index(ReportList *reports, + Object *ob, + bConstraint *con, + const int index) +{ + BLI_assert(con != NULL); + BLI_assert(index >= 0); + + ListBase *conlist = ED_object_constraint_list_from_constraint(ob, con, NULL); + int current_index = BLI_findindex(conlist, con); + BLI_assert(current_index >= 0); + + BLI_listbase_link_move(conlist, con, index - current_index); + + return true; +} + /** \} */ /* ------------------------------------------------------------------- */ @@ -1613,11 +1631,7 @@ static int constraint_move_to_index_exec(bContext *C, wmOperator *op) } if (con) { - ListBase *conlist = ED_object_constraint_list_from_constraint(ob, con, NULL); - int current_index = BLI_findindex(conlist, con); - BLI_assert(current_index >= 0); - - BLI_listbase_link_move(conlist, con, new_index - current_index); + ED_object_constraint_move_to_index(op->reports, ob, con, new_index); WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index 5004b0132c2..27a641dc6d8 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -2569,14 +2569,12 @@ BLI_INLINE bool streq_array_any(const char *s, const char *arr[]) * correct old \a uiBlock, and NULL otherwise. */ static void ed_panel_draw(const bContext *C, - ScrArea *area, ARegion *region, ListBase *lb, PanelType *pt, Panel *panel, int w, int em, - bool vertical, char *unique_panel_str) { const uiStyle *style = UI_style_get_dpi(); @@ -2592,13 +2590,13 @@ static void ed_panel_draw(const bContext *C, uiBlock *block = UI_block_begin(C, region, block_name, UI_EMBOSS); bool open; - panel = UI_panel_begin(area, region, lb, block, pt, panel, &open); + panel = UI_panel_begin(region, lb, block, pt, panel, &open); /* bad fixed values */ int xco, yco, h = 0; int headerend = w - UI_UNIT_X; - if (pt->draw_header_preset && !(pt->flag & PNL_NO_HEADER) && (open || vertical)) { + if (pt->draw_header_preset && !(pt->flag & PNL_NO_HEADER)) { /* for preset menu */ panel->layout = UI_block_layout(block, UI_LAYOUT_HORIZONTAL, @@ -2617,7 +2615,7 @@ static void ed_panel_draw(const bContext *C, panel->layout = NULL; } - if (pt->draw_header && !(pt->flag & PNL_NO_HEADER) && (open || vertical)) { + if (pt->draw_header && !(pt->flag & PNL_NO_HEADER)) { int labelx, labely; UI_panel_label_offset(block, &labelx, &labely); @@ -2694,21 +2692,12 @@ static void ed_panel_draw(const bContext *C, Panel *child_panel = UI_panel_find_by_type(&panel->children, child_pt); if (child_pt->draw && (!child_pt->poll || child_pt->poll(C, child_pt))) { - ed_panel_draw(C, - area, - region, - &panel->children, - child_pt, - child_panel, - w, - em, - vertical, - unique_panel_str); + ed_panel_draw(C, region, &panel->children, child_pt, child_panel, w, em, unique_panel_str); } } } - UI_panel_end(area, region, block, w, h, open); + UI_panel_end(region, block, w, h, open); } /** @@ -2720,8 +2709,6 @@ void ED_region_panels_layout_ex(const bContext *C, ARegion *region, ListBase *paneltypes, const char *contexts[], - int contextnr, - const bool vertical, const char *category_override) { /* collect panels to draw */ @@ -2772,25 +2759,13 @@ void ED_region_panels_layout_ex(const bContext *C, const int category_tabs_width = UI_PANEL_CATEGORY_MARGIN_WIDTH; int margin_x = 0; const bool region_layout_based = region->flag & RGN_FLAG_DYNAMIC_SIZE; - const bool is_context_new = (contextnr != -1) ? UI_view2d_tab_set(v2d, contextnr) : false; bool update_tot_size = true; - /* before setting the view */ - if (vertical) { - /* only allow scrolling in vertical direction */ - v2d->keepofs |= V2D_LOCKOFS_X | V2D_KEEPOFS_Y; - v2d->keepofs &= ~(V2D_LOCKOFS_Y | V2D_KEEPOFS_X); - v2d->scroll &= ~V2D_SCROLL_BOTTOM; - v2d->scroll |= V2D_SCROLL_RIGHT; - } - else { - /* for now, allow scrolling in both directions (since layouts are optimized for vertical, - * they often don't fit in horizontal layout) - */ - v2d->keepofs &= ~(V2D_LOCKOFS_X | V2D_LOCKOFS_Y | V2D_KEEPOFS_X | V2D_KEEPOFS_Y); - v2d->scroll |= V2D_SCROLL_BOTTOM; - v2d->scroll &= ~V2D_SCROLL_RIGHT; - } + /* only allow scrolling in vertical direction */ + v2d->keepofs |= V2D_LOCKOFS_X | V2D_KEEPOFS_Y; + v2d->keepofs &= ~(V2D_LOCKOFS_Y | V2D_KEEPOFS_X); + v2d->scroll &= ~V2D_SCROLL_BOTTOM; + v2d->scroll |= V2D_SCROLL_RIGHT; /* collect categories */ if (use_category_tabs) { @@ -2815,14 +2790,8 @@ void ED_region_panels_layout_ex(const bContext *C, } } - if (vertical) { - w = BLI_rctf_size_x(&v2d->cur); - em = (region->type->prefsizex) ? 10 : 20; /* works out to 10*UI_UNIT_X or 20*UI_UNIT_X */ - } - else { - w = UI_PANEL_WIDTH; - em = (region->type->prefsizex) ? 10 : 20; - } + w = BLI_rctf_size_x(&v2d->cur); + em = (region->type->prefsizex) ? 10 : 20; /* works out to 10*UI_UNIT_X or 20*UI_UNIT_X */ w -= margin_x; int w_box_panel = w - UI_PANEL_BOX_STYLE_MARGIN * 2.0f; @@ -2855,14 +2824,12 @@ void ED_region_panels_layout_ex(const bContext *C, } ed_panel_draw(C, - area, region, ®ion->panels, pt, panel, (pt->flag & PNL_DRAW_BOX) ? w_box_panel : w, em, - vertical, NULL); } @@ -2890,14 +2857,12 @@ void ED_region_panels_layout_ex(const bContext *C, char unique_panel_str[8]; UI_list_panel_unique_str(panel, unique_panel_str); ed_panel_draw(C, - area, region, ®ion->panels, panel->type, panel, (panel->type->flag & PNL_DRAW_BOX) ? w_box_panel : w, em, - vertical, unique_panel_str); } } @@ -2925,7 +2890,7 @@ void ED_region_panels_layout_ex(const bContext *C, y = fabsf(region->sizey * UI_DPI_FAC - 1); } } - else if (vertical) { + else { /* We always keep the scroll offset - * so the total view gets increased with the scrolled away part. */ if (v2d->cur.ymax < -FLT_EPSILON) { @@ -2940,19 +2905,6 @@ void ED_region_panels_layout_ex(const bContext *C, y = -y; } - else { - /* don't jump back when panels close or hide */ - if (!is_context_new) { - if (v2d->tot.xmax > v2d->winx) { - x = max_ii(x, 0); - } - else { - x = max_ii(x, v2d->cur.xmax); - } - } - - y = -y; - } if (update_tot_size) { /* this also changes the 'cur' */ @@ -2966,8 +2918,7 @@ void ED_region_panels_layout_ex(const bContext *C, void ED_region_panels_layout(const bContext *C, ARegion *region) { - bool vertical = true; - ED_region_panels_layout_ex(C, region, ®ion->type->paneltypes, NULL, -1, vertical, NULL); + ED_region_panels_layout_ex(C, region, ®ion->type->paneltypes, NULL, NULL); } void ED_region_panels_draw(const bContext *C, ARegion *region) @@ -3011,12 +2962,10 @@ void ED_region_panels_draw(const bContext *C, ARegion *region) UI_view2d_scrollers_draw(v2d, mask); } -void ED_region_panels_ex( - const bContext *C, ARegion *region, const char *contexts[], int contextnr, const bool vertical) +void ED_region_panels_ex(const bContext *C, ARegion *region, const char *contexts[]) { /* TODO: remove? */ - ED_region_panels_layout_ex( - C, region, ®ion->type->paneltypes, contexts, contextnr, vertical, NULL); + ED_region_panels_layout_ex(C, region, ®ion->type->paneltypes, contexts, NULL); ED_region_panels_draw(C, region); } diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index dbf84cad80b..a2509c7a330 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -1576,7 +1576,7 @@ void ED_update_for_newframe(Main *bmain, Depsgraph *depsgraph) { Scene *scene = DEG_get_input_scene(depsgraph); - DEG_id_tag_update_ex(bmain, &scene->id, ID_RECALC_TIME); + DEG_time_tag_update(bmain); #ifdef DURIAN_CAMERA_SWITCH void *camera = BKE_scene_camera_switch_find(scene); diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index 0e38340d3bc..ee514fa745c 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -566,7 +566,7 @@ static bool paint_draw_tex_overlay(UnifiedPaintSettings *ups, if (load_tex(brush, vc, zoom, col, primary)) { GPU_color_mask(true, true, true, true); - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); if (mtex->brush_map_mode == MTEX_MAP_MODE_VIEW) { GPU_matrix_push(); @@ -693,7 +693,7 @@ static bool paint_draw_cursor_overlay( float center[2]; GPU_color_mask(true, true, true, true); - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); if (ups->draw_anchored) { copy_v2_v2(center, ups->anchored_initial_mouse); @@ -776,7 +776,7 @@ static bool paint_draw_alpha_overlay(UnifiedPaintSettings *ups, ePaintOverlayControlFlags flags = BKE_paint_get_overlay_flags(); eGPUBlend blend_state = GPU_blend_get(); - bool depth_test = GPU_depth_test_enabled(); + eGPUDepthTest depth_test = GPU_depth_test_get(); /* Translate to region. */ GPU_matrix_push(); @@ -1147,9 +1147,9 @@ static void sculpt_geometry_preview_lines_draw(const uint gpuattr, immUniformColor4f(1.0f, 1.0f, 1.0f, 0.6f); /* Cursor normally draws on top, but for this part we need depth tests. */ - const bool depth_test = GPU_depth_test_enabled(); + const eGPUDepthTest depth_test = GPU_depth_test_get(); if (!depth_test) { - GPU_depth_test(true); + GPU_depth_test(GPU_DEPTH_LESS_EQUAL); } GPU_line_width(1.0f); @@ -1163,7 +1163,7 @@ static void sculpt_geometry_preview_lines_draw(const uint gpuattr, /* Restore depth test value. */ if (!depth_test) { - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); } } diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index 52cdebf3fd5..e709224f370 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -691,6 +691,14 @@ static float paint_space_stroke_spacing(bContext *C, spacing = spacing * (1.5f - spacing_pressure); } + if (SCULPT_is_cloth_deform_brush(brush)) { + /* The spacing in tools that use the cloth solver should not be affected by the brush radius to + * avoid affecting the simulation update rate when changing the radius of the brush. + With a value of 100 and the brush default of 10 for spacing, a simulation step runs every 2 + pixels movement of the cursor. */ + size_clamp = 100.0f; + } + /* stroke system is used for 2d paint too, so we need to account for * the fact that brush can be scaled there. */ spacing *= stroke->zoom_2d; @@ -1001,7 +1009,7 @@ bool paint_space_stroke_enabled(Brush *br, ePaintMode mode) return false; } - if (br->sculpt_tool == SCULPT_TOOL_CLOTH) { + if (br->sculpt_tool == SCULPT_TOOL_CLOTH || SCULPT_is_cloth_deform_brush(br)) { /* The Cloth Brush is a special case for stroke spacing. Even if it has grab modes which do * not support dynamic size, stroke spacing needs to be enabled so it is possible to control * whether the simulation runs constantly or only when the brush moves when using the cloth diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c index ea94398ee5d..cf2ed0943eb 100644 --- a/source/blender/editors/sculpt_paint/sculpt_cloth.c +++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c @@ -311,7 +311,7 @@ static void do_cloth_brush_build_constraints_task_cb_ex( else if (data->cloth_sim->deformation_pos) { /* Any other tool that target the cloth simulation handle the falloff in * their own code when modifying the deformation coordinates of the simulation, so - * deformation constraints are created with a fixed strength for all vercies. */ + * deformation constraints are created with a fixed strength for all vertices. */ cloth_brush_add_deformation_constraint( data->cloth_sim, vd.index, CLOTH_DEFORMATION_TARGET_STRENGTH); } @@ -319,7 +319,7 @@ static void do_cloth_brush_build_constraints_task_cb_ex( if (pin_simulation_boundary) { const float sim_falloff = cloth_brush_simulation_falloff_get( brush, ss->cache->initial_radius, ss->cache->location, vd.co); - /* Vertex is inside the area of the simulation without any falloff aplied. */ + /* Vertex is inside the area of the simulation without any falloff applied. */ if (sim_falloff < 1.0f) { /* Create constraints with more strength the closer the vertex is to the simulation * boundary. */ @@ -1071,6 +1071,25 @@ static EnumPropertyItem prop_cloth_filter_type[] = { {0, NULL, 0, NULL, NULL}, }; +static EnumPropertyItem prop_cloth_filter_orientation_items[] = { + {SCULPT_FILTER_ORIENTATION_LOCAL, + "LOCAL", + 0, + "Local", + "Use the local axis to limit the force and set the gravity direction"}, + {SCULPT_FILTER_ORIENTATION_WORLD, + "WORLD", + 0, + "World", + "Use the global axis to limit the force and set the gravity direction"}, + {SCULPT_FILTER_ORIENTATION_VIEW, + "VIEW", + 0, + "View", + "Use the view axis to limit the force and set the gravity direction"}, + {0, NULL, 0, NULL, NULL}, +}; + typedef enum eClothFilterForceAxis { CLOTH_FILTER_FORCE_X = 1 << 0, CLOTH_FILTER_FORCE_Y = 1 << 1, @@ -1120,7 +1139,15 @@ static void cloth_filter_apply_forces_task_cb(void *__restrict userdata, switch (filter_type) { case CLOTH_FILTER_GRAVITY: - force[2] = -data->filter_strength * fade; + if (ss->filter_cache->orientation == SCULPT_FILTER_ORIENTATION_VIEW) { + /* When using the view orientation apply gravity in the -Y axis, this way objects will + * fall down instead of backwards. */ + force[1] = -data->filter_strength * fade; + } + else { + force[2] = -data->filter_strength * fade; + } + SCULPT_filter_to_object_space(force, ss->filter_cache); break; case CLOTH_FILTER_INFLATE: { float normal[3]; @@ -1138,11 +1165,13 @@ static void cloth_filter_apply_forces_task_cb(void *__restrict userdata, break; } + SCULPT_filter_to_orientation_space(force, ss->filter_cache); for (int axis = 0; axis < 3; axis++) { if (!ss->filter_cache->enabled_force_axis[axis]) { force[axis] = 0.0f; } } + SCULPT_filter_to_object_space(force, ss->filter_cache); add_v3_v3(force, sculpt_gravity); @@ -1264,6 +1293,9 @@ static int sculpt_cloth_filter_invoke(bContext *C, wmOperator *op, const wmEvent ss->filter_cache->enabled_force_axis[1] = force_axis & CLOTH_FILTER_FORCE_Y; ss->filter_cache->enabled_force_axis[2] = force_axis & CLOTH_FILTER_FORCE_Z; + SculptFilterOrientation orientation = RNA_enum_get(op->ptr, "orientation"); + ss->filter_cache->orientation = orientation; + WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; } @@ -1297,6 +1329,12 @@ void SCULPT_OT_cloth_filter(struct wmOperatorType *ot) CLOTH_FILTER_FORCE_X | CLOTH_FILTER_FORCE_Y | CLOTH_FILTER_FORCE_Z, "Force axis", "Apply the force in the selected axis"); + RNA_def_enum(ot->srna, + "orientation", + prop_cloth_filter_orientation_items, + SCULPT_FILTER_ORIENTATION_LOCAL, + "Orientation", + "Orientation of the axis to limit the filter force"); RNA_def_float(ot->srna, "cloth_mass", 1.0f, diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c index abfbe035928..619a1b975b6 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c @@ -181,7 +181,7 @@ void SCULPT_filter_cache_free(SculptSession *ss) MEM_SAFE_FREE(ss->filter_cache); } -typedef enum eSculptMeshFilterTypes { +typedef enum eSculptMeshFilterType { MESH_FILTER_SMOOTH = 0, MESH_FILTER_SCALE = 1, MESH_FILTER_INFLATE = 2, @@ -193,7 +193,7 @@ typedef enum eSculptMeshFilterTypes { MESH_FILTER_SHARPEN = 8, MESH_FILTER_ENHANCE_DETAILS = 9, MESH_FILTER_ERASE_DISPLACEMENT = 10, -} eSculptMeshFilterTypes; +} eSculptMeshFilterType; static EnumPropertyItem prop_mesh_filter_types[] = { {MESH_FILTER_SMOOTH, "SMOOTH", 0, "Smooth", "Smooth mesh"}, @@ -258,7 +258,7 @@ static EnumPropertyItem prop_mesh_filter_orientation_items[] = { {0, NULL, 0, NULL, NULL}, }; -static bool sculpt_mesh_filter_needs_pmap(int filter_type, bool use_face_sets) +static bool sculpt_mesh_filter_needs_pmap(eSculptMeshFilterType filter_type, bool use_face_sets) { return use_face_sets || ELEM(filter_type, MESH_FILTER_SMOOTH, @@ -277,7 +277,7 @@ static void mesh_filter_task_cb(void *__restrict userdata, SculptSession *ss = data->ob->sculpt; PBVHNode *node = data->nodes[i]; - const int filter_type = data->filter_type; + const eSculptMeshFilterType filter_type = data->filter_type; SculptOrigVertData orig_data; SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[i]); @@ -383,7 +383,7 @@ static void mesh_filter_task_cb(void *__restrict userdata, const uint *hash_co = (const uint *)orig_co; const uint hash = BLI_hash_int_2d(hash_co[0], hash_co[1]) ^ BLI_hash_int_2d(hash_co[2], ss->filter_cache->random_seed); - mul_v3_fl(normal, hash * (1.0f / 0xFFFFFFFF) - 0.5f); + mul_v3_fl(normal, hash * (1.0f / (float)0xFFFFFFFF) - 0.5f); mul_v3_v3fl(disp, normal, fade); break; } @@ -486,49 +486,80 @@ static void mesh_filter_task_cb(void *__restrict userdata, static void mesh_filter_enhance_details_init_directions(SculptSession *ss) { const int totvert = SCULPT_vertex_count_get(ss); + FilterCache *filter_cache = ss->filter_cache; + + filter_cache->detail_directions = MEM_malloc_arrayN( + totvert, sizeof(float[3]), "detail directions"); for (int i = 0; i < totvert; i++) { float avg[3]; SCULPT_neighbor_coords_average(ss, avg, i); - sub_v3_v3v3(ss->filter_cache->detail_directions[i], avg, SCULPT_vertex_co_get(ss, i)); + sub_v3_v3v3(filter_cache->detail_directions[i], avg, SCULPT_vertex_co_get(ss, i)); } } +static void mesh_filter_surface_smooth_init(SculptSession *ss, + const float shape_preservation, + const float current_vertex_displacement) +{ + const int totvert = SCULPT_vertex_count_get(ss); + FilterCache *filter_cache = ss->filter_cache; + + filter_cache->surface_smooth_laplacian_disp = MEM_malloc_arrayN( + totvert, sizeof(float[3]), "surface smooth displacement"); + filter_cache->surface_smooth_shape_preservation = shape_preservation; + filter_cache->surface_smooth_current_vertex = current_vertex_displacement; +} + static void mesh_filter_init_limit_surface_co(SculptSession *ss) { const int totvert = SCULPT_vertex_count_get(ss); - ss->filter_cache->limit_surface_co = MEM_malloc_arrayN( - 3 * sizeof(float), totvert, "limit surface co"); + FilterCache *filter_cache = ss->filter_cache; + + filter_cache->limit_surface_co = MEM_malloc_arrayN( + sizeof(float[3]), totvert, "limit surface co"); for (int i = 0; i < totvert; i++) { - SCULPT_vertex_limit_surface_get(ss, i, ss->filter_cache->limit_surface_co[i]); + SCULPT_vertex_limit_surface_get(ss, i, filter_cache->limit_surface_co[i]); } } -static void mesh_filter_sharpen_init_factors(SculptSession *ss) +static void mesh_filter_sharpen_init(SculptSession *ss, + const float smooth_ratio, + const float intensify_detail_strength, + const int curvature_smooth_iterations) { const int totvert = SCULPT_vertex_count_get(ss); + FilterCache *filter_cache = ss->filter_cache; + + filter_cache->sharpen_smooth_ratio = smooth_ratio; + filter_cache->sharpen_intensify_detail_strength = intensify_detail_strength; + filter_cache->sharpen_curvature_smooth_iterations = curvature_smooth_iterations; + filter_cache->sharpen_factor = MEM_malloc_arrayN(sizeof(float), totvert, "sharpen factor"); + filter_cache->detail_directions = MEM_malloc_arrayN( + totvert, sizeof(float[3]), "sharpen detail direction"); + for (int i = 0; i < totvert; i++) { float avg[3]; SCULPT_neighbor_coords_average(ss, avg, i); - sub_v3_v3v3(ss->filter_cache->detail_directions[i], avg, SCULPT_vertex_co_get(ss, i)); - ss->filter_cache->sharpen_factor[i] = len_v3(ss->filter_cache->detail_directions[i]); + sub_v3_v3v3(filter_cache->detail_directions[i], avg, SCULPT_vertex_co_get(ss, i)); + filter_cache->sharpen_factor[i] = len_v3(filter_cache->detail_directions[i]); } float max_factor = 0.0f; for (int i = 0; i < totvert; i++) { - if (ss->filter_cache->sharpen_factor[i] > max_factor) { - max_factor = ss->filter_cache->sharpen_factor[i]; + if (filter_cache->sharpen_factor[i] > max_factor) { + max_factor = filter_cache->sharpen_factor[i]; } } max_factor = 1.0f / max_factor; for (int i = 0; i < totvert; i++) { - ss->filter_cache->sharpen_factor[i] *= max_factor; - ss->filter_cache->sharpen_factor[i] = 1.0f - pow2f(1.0f - ss->filter_cache->sharpen_factor[i]); + filter_cache->sharpen_factor[i] *= max_factor; + filter_cache->sharpen_factor[i] = 1.0f - pow2f(1.0f - filter_cache->sharpen_factor[i]); } /* Smooth the calculated factors and directions to remove high frecuency detail. */ for (int smooth_iterations = 0; - smooth_iterations < ss->filter_cache->sharpen_curvature_smooth_iterations; + smooth_iterations < filter_cache->sharpen_curvature_smooth_iterations; smooth_iterations++) { for (int i = 0; i < totvert; i++) { float direction_avg[3] = {0.0f, 0.0f, 0.0f}; @@ -537,15 +568,15 @@ static void mesh_filter_sharpen_init_factors(SculptSession *ss) SculptVertexNeighborIter ni; SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) { - add_v3_v3(direction_avg, ss->filter_cache->detail_directions[ni.index]); - sharpen_avg += ss->filter_cache->sharpen_factor[ni.index]; + add_v3_v3(direction_avg, filter_cache->detail_directions[ni.index]); + sharpen_avg += filter_cache->sharpen_factor[ni.index]; total++; } SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); if (total > 0) { - mul_v3_v3fl(ss->filter_cache->detail_directions[i], direction_avg, 1.0f / total); - ss->filter_cache->sharpen_factor[i] = sharpen_avg / total; + mul_v3_v3fl(filter_cache->detail_directions[i], direction_avg, 1.0f / total); + filter_cache->sharpen_factor[i] = sharpen_avg / total; } } } @@ -590,7 +621,7 @@ static int sculpt_mesh_filter_modal(bContext *C, wmOperator *op, const wmEvent * Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); SculptSession *ss = ob->sculpt; Sculpt *sd = CTX_data_tool_settings(C)->sculpt; - int filter_type = RNA_enum_get(op->ptr, "type"); + eSculptMeshFilterType filter_type = RNA_enum_get(op->ptr, "type"); float filter_strength = RNA_float_get(op->ptr, "strength"); const bool use_face_sets = RNA_boolean_get(op->ptr, "use_face_sets"); @@ -654,17 +685,21 @@ static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent Object *ob = CTX_data_active_object(C); Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); Sculpt *sd = CTX_data_tool_settings(C)->sculpt; - int filter_type = RNA_enum_get(op->ptr, "type"); SculptSession *ss = ob->sculpt; - PBVH *pbvh = ob->sculpt->pbvh; - int deform_axis = RNA_enum_get(op->ptr, "deform_axis"); + const eMeshFilterDeformAxis deform_axis = RNA_enum_get(op->ptr, "deform_axis"); + const eSculptMeshFilterType filter_type = RNA_enum_get(op->ptr, "type"); + const bool use_face_sets = RNA_boolean_get(op->ptr, "use_face_sets"); + const bool needs_topology_info = sculpt_mesh_filter_needs_pmap(filter_type, use_face_sets); + if (deform_axis == 0) { + /* All axis are disabled, so the filter is not going to produce any deformation. */ return OPERATOR_CANCELLED; } - if (RNA_boolean_get(op->ptr, "use_face_sets")) { - /* Update the active vertex */ + if (use_face_sets) { + /* Update the active face set manually as the paint cursor is not enabled when using the Mesh + * Filter Tool. */ float mouse[2]; SculptCursorGeometryInfo sgi; mouse[0] = event->mval[0]; @@ -672,67 +707,48 @@ static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false); } - const bool use_face_sets = RNA_boolean_get(op->ptr, "use_face_sets"); - SCULPT_vertex_random_access_ensure(ss); - - const bool needs_topology_info = sculpt_mesh_filter_needs_pmap(filter_type, use_face_sets); BKE_sculpt_update_object_for_edit(depsgraph, ob, needs_topology_info, false, false); if (needs_topology_info) { SCULPT_boundary_info_ensure(ob); } - const int totvert = SCULPT_vertex_count_get(ss); - if (BKE_pbvh_type(pbvh) == PBVH_FACES && needs_topology_info && !ob->sculpt->pmap) { - return OPERATOR_CANCELLED; - } - - SCULPT_undo_push_begin("Mesh filter"); - - if (ELEM(filter_type, MESH_FILTER_RELAX, MESH_FILTER_RELAX_FACE_SETS)) { - SCULPT_boundary_info_ensure(ob); - } + SCULPT_undo_push_begin("Mesh Filter"); SCULPT_filter_cache_init(C, ob, sd, SCULPT_UNDO_COORDS); - if (use_face_sets) { - ss->filter_cache->active_face_set = SCULPT_active_face_set_get(ss); - } - else { - ss->filter_cache->active_face_set = SCULPT_FACE_SET_NONE; - } - - if (RNA_enum_get(op->ptr, "type") == MESH_FILTER_SURFACE_SMOOTH) { - ss->filter_cache->surface_smooth_laplacian_disp = MEM_mallocN(sizeof(float[3]) * totvert, - "surface smooth disp"); - ss->filter_cache->surface_smooth_shape_preservation = RNA_float_get( - op->ptr, "surface_smooth_shape_preservation"); - ss->filter_cache->surface_smooth_current_vertex = RNA_float_get( - op->ptr, "surface_smooth_current_vertex"); - } - - if (RNA_enum_get(op->ptr, "type") == MESH_FILTER_SHARPEN) { - ss->filter_cache->sharpen_smooth_ratio = RNA_float_get(op->ptr, "sharpen_smooth_ratio"); - ss->filter_cache->sharpen_intensify_detail_strength = RNA_float_get( - op->ptr, "sharpen_intensify_detail_strength"); - ss->filter_cache->sharpen_curvature_smooth_iterations = RNA_int_get( - op->ptr, "sharpen_curvature_smooth_iterations"); - - ss->filter_cache->sharpen_factor = MEM_mallocN(sizeof(float) * totvert, "sharpen factor"); - ss->filter_cache->detail_directions = MEM_malloc_arrayN( - totvert, sizeof(float[3]), "sharpen detail direction"); - - mesh_filter_sharpen_init_factors(ss); - } - - if (RNA_enum_get(op->ptr, "type") == MESH_FILTER_ENHANCE_DETAILS) { - ss->filter_cache->detail_directions = MEM_malloc_arrayN( - totvert, sizeof(float[3]), "detail direction"); - mesh_filter_enhance_details_init_directions(ss); - } + FilterCache *filter_cache = ss->filter_cache; + filter_cache->active_face_set = use_face_sets ? SCULPT_active_face_set_get(ss) : + SCULPT_FACE_SET_NONE; - if (RNA_enum_get(op->ptr, "type") == MESH_FILTER_ERASE_DISPLACEMENT) { - mesh_filter_init_limit_surface_co(ss); + switch (filter_type) { + case MESH_FILTER_SURFACE_SMOOTH: { + const float shape_preservation = RNA_float_get(op->ptr, "surface_smooth_shape_preservation"); + const float current_vertex_displacement = RNA_float_get(op->ptr, + "surface_smooth_current_vertex"); + mesh_filter_surface_smooth_init(ss, shape_preservation, current_vertex_displacement); + break; + } + case MESH_FILTER_SHARPEN: { + const float smooth_ratio = RNA_float_get(op->ptr, "sharpen_smooth_ratio"); + const float intensify_detail_strength = RNA_float_get(op->ptr, + "sharpen_intensify_detail_strength"); + const int curvature_smooth_iterations = RNA_int_get(op->ptr, + "sharpen_curvature_smooth_iterations"); + mesh_filter_sharpen_init( + ss, smooth_ratio, intensify_detail_strength, curvature_smooth_iterations); + break; + } + case MESH_FILTER_ENHANCE_DETAILS: { + mesh_filter_enhance_details_init_directions(ss); + break; + } + case MESH_FILTER_ERASE_DISPLACEMENT: { + mesh_filter_init_limit_surface_co(ss); + break; + } + default: + break; } ss->filter_cache->enabled_axis[0] = deform_axis & MESH_FILTER_DEFORM_X; diff --git a/source/blender/editors/sculpt_paint/sculpt_transform.c b/source/blender/editors/sculpt_paint/sculpt_transform.c index bdada4d2565..b52b04eba3a 100644 --- a/source/blender/editors/sculpt_paint/sculpt_transform.c +++ b/source/blender/editors/sculpt_paint/sculpt_transform.c @@ -326,6 +326,12 @@ static int sculpt_set_pivot_position_exec(bContext *C, wmOperator *op) MEM_SAFE_FREE(nodes); } + /* Update the viewport navigation rotation origin. */ + UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings; + copy_v3_v3(ups->average_stroke_accum, ss->pivot_pos); + ups->average_stroke_counter = 1; + ups->last_stroke_valid = true; + ED_region_tag_redraw(region); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data); diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c index 3976e18d70c..bd5d7826d0e 100644 --- a/source/blender/editors/space_buttons/buttons_context.c +++ b/source/blender/editors/space_buttons/buttons_context.c @@ -535,11 +535,11 @@ static bool buttons_context_linestyle_pinnable(const bContext *C, ViewLayer *vie } #endif -static bool buttons_context_path(const bContext *C, ButsContextPath *path, int mainb, int flag) +static bool buttons_context_path( + const bContext *C, SpaceProperties *sbuts, ButsContextPath *path, int mainb, int flag) { /* Note we don't use CTX_data here, instead we get it from the window. * Otherwise there is a loop reading the context that we are setting. */ - SpaceProperties *sbuts = CTX_wm_space_properties(C); wmWindow *window = CTX_wm_window(C); Scene *scene = WM_window_get_active_scene(window); ViewLayer *view_layer = WM_window_get_active_view_layer(window); @@ -685,14 +685,14 @@ void buttons_context_compute(const bContext *C, SpaceProperties *sbuts) path = sbuts->path; /* Set scene path. */ - buttons_context_path(C, path, BCONTEXT_SCENE, pflag); + buttons_context_path(C, sbuts, path, BCONTEXT_SCENE, pflag); buttons_texture_context_compute(C, sbuts); /* for each context, see if we can compute a valid path to it, if * this is the case, we know we have to display the button */ for (a = 0; a < BCONTEXT_TOT; a++) { - if (buttons_context_path(C, path, a, pflag)) { + if (buttons_context_path(C, sbuts, path, a, pflag)) { flag |= (1 << a); /* setting icon for data context */ @@ -738,7 +738,7 @@ void buttons_context_compute(const bContext *C, SpaceProperties *sbuts) } } - buttons_context_path(C, path, sbuts->mainb, pflag); + buttons_context_path(C, sbuts, path, sbuts->mainb, pflag); if (!(flag & (1 << sbuts->mainb))) { if (flag & (1 << BCONTEXT_OBJECT)) { @@ -759,6 +759,38 @@ void buttons_context_compute(const bContext *C, SpaceProperties *sbuts) sbuts->pathflag = flag; } +static bool is_pointer_in_path(ButsContextPath *path, PointerRNA *ptr) +{ + for (int i = 0; i < path->len; ++i) { + if (ptr->owner_id == path->ptr[i].owner_id) { + return true; + } + } + return false; +} + +void ED_buttons_set_context(const bContext *C, PointerRNA *ptr, const short context) +{ + bScreen *screen = CTX_wm_screen(C); + + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + /* Only update for properties editors that are visible */ + SpaceLink *sl = area->spacedata.first; + + if (sl->spacetype == SPACE_PROPERTIES) { + SpaceProperties *sbuts = (SpaceProperties *)sl; + + ButsContextPath path; + if (buttons_context_path(C, sbuts, &path, context, 0)) { + if (is_pointer_in_path(&path, ptr)) { + sbuts->mainbuser = context; + sbuts->mainb = sbuts->mainbuser; + } + } + } + } +} + /************************* Context Callback ************************/ const char *buttons_context_dir[] = { diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index dc34e56dc92..d7cf2e4d544 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -292,9 +292,7 @@ static void buttons_main_region_layout_properties(const bContext *C, break; } - const bool vertical = true; - ED_region_panels_layout_ex( - C, region, ®ion->type->paneltypes, contexts, sbuts->mainb, vertical, NULL); + ED_region_panels_layout_ex(C, region, ®ion->type->paneltypes, contexts, NULL); } static void buttons_main_region_layout(const bContext *C, ARegion *region) diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c index d58f5ede7d7..058436a46bf 100644 --- a/source/blender/editors/space_image/image_draw.c +++ b/source/blender/editors/space_image/image_draw.c @@ -523,7 +523,7 @@ static void sima_draw_zbuffloat_pixels(Scene *scene, GPU_shader_uniform_vector( state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, red); - immDrawPixelsTex(&state, x1, y1, rectx, recty, GL_R16F, false, rectf, zoomx, zoomy, NULL); + immDrawPixelsTex(&state, x1, y1, rectx, recty, GPU_R16F, false, rectf, zoomx, zoomy, NULL); MEM_freeN(rectf); } diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index a64d5505ebe..1f7929cea7b 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -662,7 +662,7 @@ static void image_main_region_draw(const bContext *C, ARegion *region) srgb_to_linearrgb_v3_v3(col, col); GPU_clear_color(col[0], col[1], col[2], 1.0f); GPU_clear(GPU_COLOR_BIT); - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); image_user_refresh_scene(C, sima); @@ -836,9 +836,7 @@ static void image_buttons_region_layout(const bContext *C, ARegion *region) break; } - const bool vertical = true; - ED_region_panels_layout_ex( - C, region, ®ion->type->paneltypes, contexts_base, -1, vertical, NULL); + ED_region_panels_layout_ex(C, region, ®ion->type->paneltypes, contexts_base, NULL); } static void image_buttons_region_draw(const bContext *C, ARegion *region) diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c index 4e91da01cc9..e97031736ca 100644 --- a/source/blender/editors/space_info/info_stats.c +++ b/source/blender/editors/space_info/info_stats.c @@ -547,19 +547,20 @@ static void get_stats_string( info + *ofs, len - *ofs, TIP_(" | Objects:%s/%s"), stats_fmt->totobjsel, stats_fmt->totobj); } -const char *ED_info_statusbar_string(Main *bmain, bScreen *screen, bContext *C) +static const char *info_statusbar_string(Main *bmain, + Scene *scene, + ViewLayer *view_layer, + char statusbar_flag) { char formatted_mem[15]; size_t ofs = 0; - char *info = screen->statusbar_info; - int len = sizeof(screen->statusbar_info); + static char info[256]; + int len = sizeof(info); info[0] = '\0'; /* Scene statistics. */ - if (U.statusbar_flag & STATUSBAR_SHOW_STATS) { - ViewLayer *view_layer = CTX_data_view_layer(C); - Scene *scene = CTX_data_scene(C); + if (statusbar_flag & STATUSBAR_SHOW_STATS) { SceneStatsFmt stats_fmt; if (format_stats(bmain, scene, view_layer, &stats_fmt)) { get_stats_string(info + ofs, len, &ofs, view_layer, &stats_fmt); @@ -567,7 +568,7 @@ const char *ED_info_statusbar_string(Main *bmain, bScreen *screen, bContext *C) } /* Memory status. */ - if (U.statusbar_flag & STATUSBAR_SHOW_MEMORY) { + if (statusbar_flag & STATUSBAR_SHOW_MEMORY) { if (info[0]) { ofs += BLI_snprintf(info + ofs, len - ofs, " | "); } @@ -577,7 +578,7 @@ const char *ED_info_statusbar_string(Main *bmain, bScreen *screen, bContext *C) } /* GPU VRAM status. */ - if ((U.statusbar_flag & STATUSBAR_SHOW_VRAM) && (GPU_mem_stats_supported())) { + if ((statusbar_flag & STATUSBAR_SHOW_VRAM) && (GPU_mem_stats_supported())) { int gpu_free_mem_kb, gpu_tot_mem_kb; GPU_mem_stats_get(&gpu_tot_mem_kb, &gpu_free_mem_kb); float gpu_total_gb = gpu_tot_mem_kb / 1048576.0f; @@ -599,7 +600,7 @@ const char *ED_info_statusbar_string(Main *bmain, bScreen *screen, bContext *C) } /* Blender version. */ - if (U.statusbar_flag & STATUSBAR_SHOW_VERSION) { + if (statusbar_flag & STATUSBAR_SHOW_VERSION) { if (info[0]) { ofs += BLI_snprintf(info + ofs, len - ofs, " | "); } @@ -609,6 +610,20 @@ const char *ED_info_statusbar_string(Main *bmain, bScreen *screen, bContext *C) return info; } +const char *ED_info_statusbar_string(Main *bmain, Scene *scene, ViewLayer *view_layer) +{ + return info_statusbar_string(bmain, scene, view_layer, U.statusbar_flag); +} + +const char *ED_info_statistics_string(Main *bmain, Scene *scene, ViewLayer *view_layer) +{ + const eUserpref_StatusBar_Flag statistics_status_bar_flag = STATUSBAR_SHOW_STATS | + STATUSBAR_SHOW_MEMORY | + STATUSBAR_SHOW_VERSION; + + return info_statusbar_string(bmain, scene, view_layer, statistics_status_bar_flag); +} + static void stats_row(int col1, const char *key, int col2, diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c index bc9bd0e18f2..dc8f616c5e6 100644 --- a/source/blender/editors/space_nla/nla_edit.c +++ b/source/blender/editors/space_nla/nla_edit.c @@ -1847,11 +1847,7 @@ static int nlaedit_sync_actlen_exec(bContext *C, wmOperator *op) continue; } - /* recalculate the length of the action */ - calc_action_range(strip->act, &strip->actstart, &strip->actend, 0); - - /* adjust the strip extents in response to this */ - BKE_nlastrip_recalculate_bounds(strip); + BKE_nlastrip_recalculate_bounds_sync_action(strip); ale->update |= ANIM_UPDATE_DEPS; } diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c index e36dc2f4906..917bb8e75fd 100644 --- a/source/blender/editors/space_node/node_draw.c +++ b/source/blender/editors/space_node/node_draw.c @@ -867,7 +867,7 @@ void ED_node_socket_draw(bNodeSocket *sock, const rcti *rect, const float color[ /* ************** Socket callbacks *********** */ -static void node_draw_preview_background(float tile, rctf *rect) +static void node_draw_preview_background(rctf *rect) { GPUVertFormat *format = immVertexFormat(); uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); @@ -909,7 +909,7 @@ static void node_draw_preview(bNodePreview *preview, rctf *prv) scale = yscale; } - node_draw_preview_background(BLI_rctf_size_x(prv) / 10.0f, &draw_rect); + node_draw_preview_background(&draw_rect); GPU_blend(GPU_BLEND_ALPHA); /* premul graphics */ @@ -1738,7 +1738,7 @@ void drawnodespace(const bContext *C, ARegion *region) UI_view2d_view_ortho(v2d); UI_ThemeClearColor(TH_BACK); GPU_clear(GPU_COLOR_BIT); - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); /* XXX snode->cursor set in coordspace for placing new nodes, used for drawing noodles too */ UI_view2d_region_to_view(®ion->v2d, diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c index a76ee2972cc..fbc6a8b18f1 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -183,70 +183,71 @@ static bool outliner_view_layer_collections_editor_poll(bContext *C) /** \name New Collection * \{ */ -struct CollectionNewData { - bool error; - Collection *collection; -}; - -static TreeTraversalAction collection_find_selected_to_add(TreeElement *te, void *customdata) -{ - struct CollectionNewData *data = customdata; - Collection *collection = outliner_collection_from_tree_element(te); - - if (!collection) { - return TRAVERSE_SKIP_CHILDS; - } - - if (data->collection != NULL) { - data->error = true; - return TRAVERSE_BREAK; +typedef enum NewCollectionType { + COLLECTION_NEW_EMPTY, + COLLECTION_NEW_FROM_SELECTION, + COLLECTION_NEW_FROM_SELECTION_LINKED, +} NewCollectionType; + +static Collection *find_parent_collection(TreeElement *te) +{ + while (te) { + te = te->parent; + if (outliner_is_collection_tree_element(te)) { + return outliner_collection_from_tree_element(te); + } } - - data->collection = collection; - return TRAVERSE_CONTINUE; + return NULL; } static int collection_new_exec(bContext *C, wmOperator *op) { SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); - ARegion *region = CTX_wm_region(C); Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); + Collection *collection; + const short type = RNA_enum_get(op->ptr, "type"); - struct CollectionNewData data = { - .error = false, - .collection = NULL, - }; + /* Make new collection a child of the active collection */ + collection = CTX_data_layer_collection(C)->collection; + if (ID_IS_LINKED(collection)) { + collection = scene->master_collection; + } + + if (ID_IS_LINKED(scene)) { + BKE_report(op->reports, RPT_ERROR, "Can't add a new collection to linked scene/collection"); + return OPERATOR_CANCELLED; + } - if (RNA_boolean_get(op->ptr, "nested")) { - outliner_build_tree(bmain, scene, view_layer, space_outliner, region); + Collection *collection_new = BKE_collection_add(bmain, collection, NULL); + if (type != COLLECTION_NEW_EMPTY) { + /* Move selected objects into new collection */ + struct IDsSelectedData data = {{NULL}}; outliner_tree_traverse(space_outliner, &space_outliner->tree, 0, TSE_SELECTED, - collection_find_selected_to_add, + outliner_find_selected_objects, &data); - if (data.error) { - BKE_report(op->reports, RPT_ERROR, "More than one collection is selected"); - return OPERATOR_CANCELLED; - } - } - - if (data.collection == NULL || ID_IS_LINKED(data.collection)) { - data.collection = scene->master_collection; - } + LISTBASE_FOREACH (LinkData *, link, &data.selected_array) { + TreeElement *te = (TreeElement *)link->data; + TreeStoreElem *tselem = TREESTORE(te); + Collection *parent = find_parent_collection(te); + Object *ob = (Object *)tselem->id; - if (ID_IS_LINKED(scene)) { - BKE_report(op->reports, RPT_ERROR, "Can't add a new collection to linked scene/collection"); - return OPERATOR_CANCELLED; + if (type == COLLECTION_NEW_FROM_SELECTION) { + BKE_collection_object_move(bmain, scene, collection_new, parent, ob); + } + else { + BKE_collection_object_add(bmain, collection_new, ob); + } + } + BLI_freelistN(&data.selected_array); } - BKE_collection_add(bmain, data.collection, NULL); - - DEG_id_tag_update(&data.collection->id, ID_RECALC_COPY_ON_WRITE); + DEG_id_tag_update(&collection->id, ID_RECALC_COPY_ON_WRITE); DEG_relations_tag_update(bmain); outliner_cleanup_tree(space_outliner); @@ -256,10 +257,29 @@ static int collection_new_exec(bContext *C, wmOperator *op) void OUTLINER_OT_collection_new(wmOperatorType *ot) { + static EnumPropertyItem type_items[] = { + {COLLECTION_NEW_EMPTY, + "EMPTY", + 0, + "Empty", + "Create a new collection inside the active collection"}, + {COLLECTION_NEW_FROM_SELECTION, + "SELECTION", + 0, + "Move Objects", + "Move the selected objects to a new collection"}, + {COLLECTION_NEW_FROM_SELECTION_LINKED, + "SELECTION_LINKED", + 0, + "Link Objects", + "Link the selected objects to a new collection"}, + {0, NULL, 0, NULL, NULL}, + }; + /* identifiers */ ot->name = "New Collection"; ot->idname = "OUTLINER_OT_collection_new"; - ot->description = "Add a new collection inside selected collection"; + ot->description = "Create a new collection"; /* api callbacks */ ot->exec = collection_new_exec; @@ -269,9 +289,7 @@ void OUTLINER_OT_collection_new(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - PropertyRNA *prop = RNA_def_boolean( - ot->srna, "nested", true, "Nested", "Add as child of selected collection"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + ot->prop = RNA_def_enum(ot->srna, "type", type_items, COLLECTION_NEW_FROM_SELECTION, "Type", ""); } /** \} */ @@ -563,7 +581,7 @@ static int collection_duplicate_exec(bContext *C, wmOperator *op) /* Can happen when calling from a key binding. */ if (te == NULL) { - BKE_report(op->reports, RPT_ERROR, "No active collection"); + BKE_reportf(op->reports, RPT_WARNING, "No active collection"); return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c index 94052223e39..6eb962dd0a1 100644 --- a/source/blender/editors/space_outliner/outliner_dragdrop.c +++ b/source/blender/editors/space_outliner/outliner_dragdrop.c @@ -26,7 +26,9 @@ #include "MEM_guardedalloc.h" #include "DNA_collection_types.h" +#include "DNA_constraint_types.h" #include "DNA_material_types.h" +#include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "DNA_space_types.h" @@ -36,6 +38,7 @@ #include "BLT_translation.h" #include "BKE_collection.h" +#include "BKE_constraint.h" #include "BKE_context.h" #include "BKE_layer.h" #include "BKE_lib_id.h" @@ -44,6 +47,7 @@ #include "BKE_object.h" #include "BKE_report.h" #include "BKE_scene.h" +#include "BKE_shader_fx.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" @@ -65,6 +69,42 @@ #include "outliner_intern.h" +static Collection *collection_parent_from_ID(ID *id); + +/* ******************** Drop Data Functions *********************** */ + +typedef struct OutlinerDropData { + Object *ob_parent; + bPoseChannel *bone_parent; + TreeStoreElem *drag_tselem; + void *drag_directdata; + int drag_index; + + int drop_action; + TreeElement *drop_te; + TreeElementInsertType insert_type; +} OutlinerDropData; + +/* */ +static void outliner_drop_data_init(wmDrag *drag, + Object *ob, + bPoseChannel *pchan, + TreeElement *te, + TreeStoreElem *tselem, + void *directdata) +{ + OutlinerDropData *drop_data = MEM_callocN(sizeof(OutlinerDropData), "outliner drop data"); + + drop_data->ob_parent = ob; + drop_data->bone_parent = pchan; + drop_data->drag_tselem = tselem; + drop_data->drag_directdata = directdata; + drop_data->drag_index = te->index; + + drag->poin = drop_data; + drag->flags |= WM_DRAG_FREE_DATA; +} + /* ******************** Drop Target Find *********************** */ static TreeElement *outliner_dropzone_element(TreeElement *te, @@ -146,7 +186,8 @@ static TreeElement *outliner_drop_insert_find(bContext *C, const float margin = UI_UNIT_Y * (1.0f / 4); if (view_mval[1] < (te_hovered->ys + margin)) { - if (TSELEM_OPEN(TREESTORE(te_hovered), space_outliner)) { + if (TSELEM_OPEN(TREESTORE(te_hovered), space_outliner) && + !BLI_listbase_is_empty(&te_hovered->subtree)) { /* inserting after a open item means we insert into it, but as first child */ if (BLI_listbase_is_empty(&te_hovered->subtree)) { *r_insert_type = TE_INSERT_INTO; @@ -212,6 +253,11 @@ static TreeElement *outliner_drop_insert_collection_find(bContext *C, return NULL; } + SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); + if (space_outliner->sort_method != SO_SORT_FREE) { + *r_insert_type = TE_INSERT_INTO; + } + if (collection_te != te) { *r_insert_type = TE_INSERT_INTO; } @@ -224,10 +270,77 @@ static TreeElement *outliner_drop_insert_collection_find(bContext *C, return collection_te; } +static Object *outliner_object_from_tree_element_and_parents(TreeElement *te, TreeElement **r_te) +{ + TreeStoreElem *tselem; + while (te != NULL) { + tselem = TREESTORE(te); + if (tselem->type == 0 && te->idcode == ID_OB) { + *r_te = te; + return (Object *)tselem->id; + } + te = te->parent; + } + return NULL; +} + +static bPoseChannel *outliner_bone_from_tree_element_and_parents(TreeElement *te, + TreeElement **r_te) +{ + TreeStoreElem *tselem; + while (te != NULL) { + tselem = TREESTORE(te); + if (tselem->type == TSE_POSE_CHANNEL) { + *r_te = te; + return (bPoseChannel *)te->directdata; + } + te = te->parent; + } + return NULL; +} + +static int outliner_get_insert_index(TreeElement *drag_te, + TreeElement *drop_te, + TreeElementInsertType insert_type, + ListBase *listbase) +{ + /* Find the element to insert after. NULL is the start of the list. */ + if (drag_te->index < drop_te->index) { + if (insert_type == TE_INSERT_BEFORE) { + drop_te = drop_te->prev; + } + } + else { + if (insert_type == TE_INSERT_AFTER) { + drop_te = drop_te->next; + } + } + + if (drop_te == NULL) { + return 0; + } + + return BLI_findindex(listbase, drop_te->directdata); +} + /* ******************** Parent Drop Operator *********************** */ -static bool parent_drop_allowed(TreeElement *te, Object *potential_child) +static bool parent_drop_allowed(bContext *C, + const wmEvent *event, + TreeElement *te, + Object *potential_child) { + ARegion *region = CTX_wm_region(C); + float view_mval[2]; + + UI_view2d_region_to_view( + ®ion->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]); + + /* Check if over name. */ + if ((view_mval[0] < te->xs + UI_UNIT_X) || (view_mval[0] > te->xend)) { + return false; + } + TreeStoreElem *tselem = TREESTORE(te); if (te->idcode != ID_OB || tselem->type != 0) { return false; @@ -262,26 +375,14 @@ static bool parent_drop_allowed(TreeElement *te, Object *potential_child) return true; } -static bool allow_parenting_without_modifier_key(SpaceOutliner *space_outliner) -{ - switch (space_outliner->outlinevis) { - case SO_VIEW_LAYER: - return space_outliner->filter & SO_FILTER_NO_COLLECTION; - case SO_SCENES: - return true; - default: - return false; - } -} - static bool parent_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event, - const char **UNUSED(r_tooltip)) + const char **r_tooltip) { SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); - bool changed = outliner_flag_set(&space_outliner->tree, TSE_DRAG_ANY, false); + bool changed = outliner_flag_set(&space_outliner->tree, TSE_HIGHLIGHTED | TSE_DRAG_ANY, false); if (changed) { ED_region_tag_redraw_no_rebuild(CTX_wm_region(C)); } @@ -291,24 +392,39 @@ static bool parent_drop_poll(bContext *C, return false; } - if (!allow_parenting_without_modifier_key(space_outliner)) { - if (!event->shift) { - return false; - } + TreeElementInsertType insert_type; + TreeElement *te = outliner_drop_insert_find(C, event, &insert_type); + if (!te) { + return false; } + TreeStoreElem *tselem = TREESTORE(te); - TreeElement *te = outliner_drop_find(C, event); - if (!te) { + if (space_outliner->sort_method != SO_SORT_FREE || space_outliner->outlinevis != SO_VIEW_LAYER) { + insert_type = TE_INSERT_INTO; + } + + if (!parent_drop_allowed(C, event, te, potential_child)) { return false; } - if (parent_drop_allowed(te, potential_child)) { - TREESTORE(te)->flag |= TSE_DRAG_INTO; - ED_region_tag_redraw_no_rebuild(CTX_wm_region(C)); - return true; + switch (insert_type) { + case TE_INSERT_BEFORE: + tselem->flag |= TSE_DRAG_BEFORE; + *r_tooltip = TIP_("Reorder object"); + break; + case TE_INSERT_AFTER: + tselem->flag |= TSE_DRAG_AFTER; + *r_tooltip = TIP_("Reorder object"); + break; + case TE_INSERT_INTO: + tselem->flag |= TSE_DRAG_INTO; + break; } - return false; + TREESTORE(te)->flag |= TSE_DRAG_INTO; + ED_region_tag_redraw_no_rebuild(CTX_wm_region(C)); + + return true; } static void parent_drop_set_parents(bContext *C, @@ -364,9 +480,50 @@ static void parent_drop_set_parents(bContext *C, } } +static void parent_drop_move_objects(bContext *C, wmDragID *drag, TreeElement *te) +{ + Main *bmain = CTX_data_main(C); + + Scene *scene = (Scene *)outliner_search_back(te, ID_SCE); + if (scene == NULL) { + scene = CTX_data_scene(C); + } + + Object *ob_drop = (Object *)TREESTORE(te)->id; + Collection *collection_to = collection_parent_from_ID(&ob_drop->id); + while (te) { + te = te->parent; + if (outliner_is_collection_tree_element(te)) { + collection_to = outliner_collection_from_tree_element(te); + break; + } + } + + for (wmDragID *drag_id = drag; drag_id; drag_id = drag_id->next) { + if (GS(drag_id->id->name) == ID_OB) { + Object *object = (Object *)drag_id->id; + + /* Do nothing to linked data */ + if (ID_IS_LINKED(object)) { + continue; + } + + Collection *from = collection_parent_from_ID(drag_id->from_parent); + BKE_collection_object_move(bmain, scene, collection_to, from, object); + BKE_collection_object_move_after(bmain, collection_to, ob_drop, object); + } + } + + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); + WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL); + WM_event_add_notifier(C, NC_SCENE | ND_LAYER, NULL); +} + static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - TreeElement *te = outliner_drop_find(C, event); + TreeElementInsertType insert_type; + TreeElement *te = outliner_drop_insert_find(C, event, &insert_type); TreeStoreElem *tselem = te ? TREESTORE(te) : NULL; if (!(te && te->idcode == ID_OB && tselem->type == 0)) { @@ -390,7 +547,17 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) ListBase *lb = event->customdata; wmDrag *drag = lb->first; - parent_drop_set_parents(C, op->reports, drag->ids.first, par, PAR_OBJECT, event->alt); + SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); + if (space_outliner->sort_method != SO_SORT_FREE || space_outliner->outlinevis != SO_VIEW_LAYER) { + insert_type = TE_INSERT_INTO; + } + + if (insert_type == TE_INSERT_INTO) { + parent_drop_set_parents(C, op->reports, drag->ids.first, par, PAR_OBJECT, event->alt); + } + else { + parent_drop_move_objects(C, drag->ids.first, te); + } return OPERATOR_FINISHED; } @@ -418,14 +585,6 @@ static bool parent_clear_poll(bContext *C, const wmEvent *event, const char **UNUSED(r_tooltip)) { - SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); - - if (!allow_parenting_without_modifier_key(space_outliner)) { - if (!event->shift) { - return false; - } - } - Object *ob = (Object *)WM_drag_ID(drag, ID_OB); if (!ob) { return false; @@ -616,6 +775,318 @@ void OUTLINER_OT_material_drop(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; } +/* ******************** UI Stack Drop Operator *********************** */ + +/* A generic operator to allow drag and drop for modifiers, constraints, + * and shader effects which all share the same UI stack layout. + * + * The following operations are allowed: + * - Reordering within an object. + * - Copying a single modifier/constraint/effect to another object. + * - Copying (linking) an object's modifiers/constraints/effects to another. */ + +enum eUIStackDropAction { + UI_STACK_DROP_REORDER, + UI_STACK_DROP_COPY, + UI_STACK_DROP_LINK, +}; + +static bool uistack_drop_poll(bContext *C, + wmDrag *drag, + const wmEvent *event, + const char **r_tooltip) +{ + OutlinerDropData *drop_data = drag->poin; + if (!drop_data) { + return false; + } + + if (!ELEM(drop_data->drag_tselem->type, + TSE_MODIFIER, + TSE_MODIFIER_BASE, + TSE_CONSTRAINT, + TSE_CONSTRAINT_BASE, + TSE_EFFECT, + TSE_EFFECT_BASE)) { + return false; + } + + SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); + ARegion *region = CTX_wm_region(C); + bool changed = outliner_flag_set(&space_outliner->tree, TSE_HIGHLIGHTED | TSE_DRAG_ANY, false); + + TreeElement *te_target = outliner_drop_insert_find(C, event, &drop_data->insert_type); + if (!te_target) { + return false; + } + TreeStoreElem *tselem_target = TREESTORE(te_target); + + if (drop_data->drag_tselem == tselem_target) { + return false; + } + + TreeElement *object_te; + TreeElement *bone_te; + Object *ob = outliner_object_from_tree_element_and_parents(te_target, &object_te); + bPoseChannel *pchan = outliner_bone_from_tree_element_and_parents(te_target, &bone_te); + if (pchan) { + ob = NULL; + } + + /* Drag a base for linking. */ + if (ELEM( + drop_data->drag_tselem->type, TSE_MODIFIER_BASE, TSE_CONSTRAINT_BASE, TSE_EFFECT_BASE)) { + drop_data->insert_type = TE_INSERT_INTO; + drop_data->drop_action = UI_STACK_DROP_LINK; + + if (pchan && pchan != drop_data->bone_parent) { + *r_tooltip = TIP_("Link all to bone"); + drop_data->drop_te = bone_te; + tselem_target = TREESTORE(bone_te); + } + else if (ob && ob != drop_data->ob_parent) { + *r_tooltip = TIP_("Link all to object"); + drop_data->drop_te = object_te; + tselem_target = TREESTORE(object_te); + } + else { + return false; + } + } + else if (ob || pchan) { + /* Drag a single item. */ + if (pchan && pchan != drop_data->bone_parent) { + *r_tooltip = TIP_("Copy to bone"); + drop_data->insert_type = TE_INSERT_INTO; + drop_data->drop_action = UI_STACK_DROP_COPY; + drop_data->drop_te = bone_te; + tselem_target = TREESTORE(bone_te); + } + else if (ob && ob != drop_data->ob_parent) { + *r_tooltip = TIP_("Copy to object"); + drop_data->insert_type = TE_INSERT_INTO; + drop_data->drop_action = UI_STACK_DROP_COPY; + drop_data->drop_te = object_te; + tselem_target = TREESTORE(object_te); + } + else if (tselem_target->type == drop_data->drag_tselem->type) { + if (drop_data->insert_type == TE_INSERT_INTO) { + return false; + } + *r_tooltip = TIP_("Reorder"); + drop_data->drop_action = UI_STACK_DROP_REORDER; + drop_data->drop_te = te_target; + } + else { + return false; + } + } + else { + return false; + } + + switch (drop_data->insert_type) { + case TE_INSERT_BEFORE: + tselem_target->flag |= TSE_DRAG_BEFORE; + break; + case TE_INSERT_AFTER: + tselem_target->flag |= TSE_DRAG_AFTER; + break; + case TE_INSERT_INTO: + tselem_target->flag |= TSE_DRAG_INTO; + break; + } + + if (changed) { + ED_region_tag_redraw_no_rebuild(region); + } + + return true; +} + +static void uistack_drop_link(bContext *C, OutlinerDropData *drop_data) +{ + Main *bmain = CTX_data_main(C); + TreeStoreElem *tselem = TREESTORE(drop_data->drop_te); + Object *ob_dst = (Object *)tselem->id; + + if (drop_data->drag_tselem->type == TSE_MODIFIER_BASE) { + BKE_object_link_modifiers(ob_dst, drop_data->ob_parent); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob_dst); + DEG_id_tag_update(&ob_dst->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); + } + else if (drop_data->drag_tselem->type == TSE_CONSTRAINT_BASE) { + ListBase *src; + + if (drop_data->bone_parent) { + src = &drop_data->bone_parent->constraints; + } + else { + src = &drop_data->ob_parent->constraints; + } + + ListBase *dst; + if (tselem->type == TSE_POSE_CHANNEL) { + bPoseChannel *pchan = (bPoseChannel *)drop_data->drop_te->directdata; + dst = &pchan->constraints; + } + else { + dst = &ob_dst->constraints; + } + + BKE_constraints_copy(dst, src, true); + LISTBASE_FOREACH (bConstraint *, con, dst) { + ED_object_constraint_dependency_tag_update(bmain, ob_dst, con); + } + WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_ADDED, NULL); + } + else if (drop_data->drag_tselem->type == TSE_EFFECT_BASE) { + if (ob_dst->type != OB_GPENCIL) { + return; + } + BKE_shaderfx_copy(&ob_dst->shader_fx, &drop_data->ob_parent->shader_fx); + + DEG_id_tag_update(&ob_dst->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_SHADERFX, ob_dst); + } +} + +static void uistack_drop_copy(bContext *C, OutlinerDropData *drop_data) +{ + Main *bmain = CTX_data_main(C); + + TreeStoreElem *tselem = TREESTORE(drop_data->drop_te); + Object *ob_dst = (Object *)tselem->id; + + if (drop_data->drag_tselem->type == TSE_MODIFIER) { + if (drop_data->ob_parent->type == OB_GPENCIL && ob_dst->type == OB_GPENCIL) { + BKE_object_link_gpencil_modifier(ob_dst, drop_data->drag_directdata); + } + else if (drop_data->ob_parent->type != OB_GPENCIL && ob_dst->type != OB_GPENCIL) { + BKE_object_link_modifier(ob_dst, drop_data->ob_parent, drop_data->drag_directdata); + } + + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob_dst); + DEG_id_tag_update(&ob_dst->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); + } + else if (drop_data->drag_tselem->type == TSE_CONSTRAINT) { + if (tselem->type == TSE_POSE_CHANNEL) { + BKE_constraint_copy_for_pose( + ob_dst, drop_data->drop_te->directdata, drop_data->drag_directdata); + } + else { + BKE_constraint_copy_for_object(ob_dst, drop_data->drag_directdata); + } + + ED_object_constraint_dependency_tag_update(bmain, ob_dst, drop_data->drag_directdata); + WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_ADDED, ob_dst); + } + else if (drop_data->drag_tselem->type == TSE_EFFECT) { + if (ob_dst->type != OB_GPENCIL) { + return; + } + ShaderFxData *fx = drop_data->drag_directdata; + ShaderFxData *nfx = BKE_shaderfx_new(fx->type); + BLI_strncpy(nfx->name, fx->name, sizeof(nfx->name)); + BKE_shaderfx_copydata(fx, nfx); + BLI_addtail(&ob_dst->shader_fx, nfx); + + DEG_id_tag_update(&ob_dst->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_SHADERFX, ob_dst); + } +} + +static void uistack_drop_reorder(bContext *C, ReportList *reports, OutlinerDropData *drop_data) +{ + SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); + + TreeElement *drag_te = outliner_find_tree_element(&space_outliner->tree, drop_data->drag_tselem); + if (!drag_te) { + return; + } + + TreeElement *drop_te = drop_data->drop_te; + TreeStoreElem *tselem = TREESTORE(drop_data->drop_te); + TreeElementInsertType insert_type = drop_data->insert_type; + + Object *ob_dst = (Object *)tselem->id; + Object *ob = drop_data->ob_parent; + + int index = 0; + if (drop_data->drag_tselem->type == TSE_MODIFIER) { + if (ob->type == OB_GPENCIL && ob_dst->type == OB_GPENCIL) { + index = outliner_get_insert_index( + drag_te, drop_te, insert_type, &ob->greasepencil_modifiers); + ED_object_gpencil_modifier_move_to_index(reports, ob, drop_data->drag_directdata, index); + } + else if (ob->type != OB_GPENCIL && ob_dst->type != OB_GPENCIL) { + index = outliner_get_insert_index(drag_te, drop_te, insert_type, &ob->modifiers); + ED_object_modifier_move_to_index(reports, ob, drop_data->drag_directdata, index); + } + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + } + else if (drop_data->drag_tselem->type == TSE_CONSTRAINT) { + if (drop_data->bone_parent) { + index = outliner_get_insert_index( + drag_te, drop_te, insert_type, &drop_data->bone_parent->constraints); + } + else { + index = outliner_get_insert_index(drag_te, drop_te, insert_type, &ob->constraints); + } + ED_object_constraint_move_to_index(reports, ob, drop_data->drag_directdata, index); + WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); + } + else if (drop_data->drag_tselem->type == TSE_EFFECT) { + index = outliner_get_insert_index(drag_te, drop_te, insert_type, &ob->shader_fx); + ED_object_shaderfx_move_to_index(reports, ob, drop_data->drag_directdata, index); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_SHADERFX, ob); + } +} + +static int uistack_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + if (event->custom != EVT_DATA_DRAGDROP) { + return OPERATOR_CANCELLED; + } + + ListBase *lb = event->customdata; + wmDrag *drag = lb->first; + OutlinerDropData *drop_data = drag->poin; + + switch (drop_data->drop_action) { + case UI_STACK_DROP_LINK: + uistack_drop_link(C, drop_data); + break; + case UI_STACK_DROP_COPY: + uistack_drop_copy(C, drop_data); + break; + case UI_STACK_DROP_REORDER: + uistack_drop_reorder(C, op->reports, drop_data); + break; + } + + return OPERATOR_FINISHED; +} + +void OUTLINER_OT_uistack_drop(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "UI Stack Drop"; + ot->description = "Copy or reorder modifiers, constraints, and effects"; + ot->idname = "OUTLINER_OT_uistack_drop"; + + /* api callbacks */ + ot->invoke = uistack_drop_invoke; + + ot->poll = ED_operator_outliner_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; +} + /* ******************** Collection Drop Operator *********************** */ typedef struct CollectionDrop { @@ -730,22 +1201,12 @@ static bool collection_drop_poll(bContext *C, case TE_INSERT_BEFORE: tselem->flag |= TSE_DRAG_BEFORE; changed = true; - if (te->prev && outliner_is_collection_tree_element(te->prev)) { - *r_tooltip = TIP_("Move between collections"); - } - else { - *r_tooltip = TIP_("Move before collection"); - } + *r_tooltip = TIP_("Reorder collection(s)"); break; case TE_INSERT_AFTER: tselem->flag |= TSE_DRAG_AFTER; changed = true; - if (te->next && outliner_is_collection_tree_element(te->next)) { - *r_tooltip = TIP_("Move between collections"); - } - else { - *r_tooltip = TIP_("Move after collection"); - } + *r_tooltip = TIP_("Reorder collection(s)"); break; case TE_INSERT_INTO: tselem->flag |= TSE_DRAG_INTO; @@ -882,7 +1343,8 @@ static int outliner_item_drag_drop_invoke(bContext *C, return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); } - TreeElementIcon data = tree_element_get_icon(TREESTORE(te), te); + TreeStoreElem *tselem = TREESTORE(te); + TreeElementIcon data = tree_element_get_icon(tselem, te); if (!data.drag_id) { return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); } @@ -893,6 +1355,9 @@ static int outliner_item_drag_drop_invoke(bContext *C, if (outliner_item_is_co_within_close_toggle(te, view_mval[0])) { return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); } + if (outliner_is_co_within_mode_column(space_outliner, view_mval)) { + return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; + } /* Scroll the view when dragging near edges, but not * when the drag goes too far outside the region. */ @@ -907,13 +1372,25 @@ static int outliner_item_drag_drop_invoke(bContext *C, wmDrag *drag = WM_event_start_drag(C, data.icon, WM_DRAG_ID, NULL, 0.0, WM_DRAG_NOP); - if (ELEM(GS(data.drag_id->name), ID_OB, ID_GR)) { + if (ELEM(tselem->type, + TSE_MODIFIER, + TSE_MODIFIER_BASE, + TSE_CONSTRAINT, + TSE_CONSTRAINT_BASE, + TSE_EFFECT, + TSE_EFFECT_BASE)) { + + TreeElement *te_bone = NULL; + bPoseChannel *pchan = outliner_find_parent_bone(te, &te_bone); + outliner_drop_data_init(drag, (Object *)tselem->id, pchan, te, tselem, te->directdata); + } + else if (ELEM(GS(data.drag_id->name), ID_OB, ID_GR)) { /* For collections and objects we cheat and drag all selected. */ /* Only drag element under mouse if it was not selected before. */ - if ((TREESTORE(te)->flag & TSE_SELECTED) == 0) { + if ((tselem->flag & TSE_SELECTED) == 0) { outliner_flag_set(&space_outliner->tree, TSE_SELECTED, 0); - TREESTORE(te)->flag |= TSE_SELECTED; + tselem->flag |= TSE_SELECTED; } /* Gather all selected elements. */ @@ -992,7 +1469,7 @@ static int outliner_item_drag_drop_invoke(bContext *C, WM_drag_add_ID(drag, data.drag_id, data.drag_parent); } - ED_outliner_select_sync_from_all_tag(C); + ED_outliner_select_sync_from_outliner(C, space_outliner); return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH); } @@ -1024,5 +1501,6 @@ void outliner_dropboxes(void) WM_dropbox_add(lb, "OUTLINER_OT_parent_clear", parent_clear_poll, NULL); WM_dropbox_add(lb, "OUTLINER_OT_scene_drop", scene_drop_poll, NULL); WM_dropbox_add(lb, "OUTLINER_OT_material_drop", material_drop_poll, NULL); + WM_dropbox_add(lb, "OUTLINER_OT_uistack_drop", uistack_drop_poll, NULL); WM_dropbox_add(lb, "OUTLINER_OT_collection_drop", collection_drop_poll, NULL); } diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index ee85864ec16..f7ad689a375 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -53,6 +53,7 @@ #include "BKE_main.h" #include "BKE_modifier.h" #include "BKE_object.h" +#include "BKE_particle.h" #include "BKE_report.h" #include "BKE_scene.h" @@ -182,7 +183,7 @@ static void restrictbutton_bone_visibility_fn(bContext *C, void *poin, void *UNU { Bone *bone = (Bone *)poin; - if (CTX_wm_window(C)->eventstate->ctrl) { + if (CTX_wm_window(C)->eventstate->shift) { restrictbutton_recursive_bone(bone, BONE_HIDDEN_P, (bone->flag & BONE_HIDDEN_P) != 0); } } @@ -194,7 +195,7 @@ static void restrictbutton_bone_select_fn(bContext *C, void *UNUSED(poin), void bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); } - if (CTX_wm_window(C)->eventstate->ctrl) { + if (CTX_wm_window(C)->eventstate->shift) { restrictbutton_recursive_bone(bone, BONE_UNSELECTABLE, (bone->flag & BONE_UNSELECTABLE) != 0); } @@ -209,7 +210,7 @@ static void restrictbutton_ebone_select_fn(bContext *C, void *UNUSED(poin), void ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); } - if (CTX_wm_window(C)->eventstate->ctrl) { + if (CTX_wm_window(C)->eventstate->shift) { restrictbutton_recursive_ebone( C, ebone, BONE_UNSELECTABLE, (ebone->flag & BONE_UNSELECTABLE) != 0); } @@ -224,7 +225,7 @@ static void restrictbutton_ebone_visibility_fn(bContext *C, void *UNUSED(poin), ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); } - if (CTX_wm_window(C)->eventstate->ctrl) { + if (CTX_wm_window(C)->eventstate->shift) { restrictbutton_recursive_ebone(C, ebone, BONE_HIDDEN_A, (ebone->flag & BONE_HIDDEN_A) != 0); } @@ -1903,6 +1904,143 @@ static void outliner_buttons(const bContext *C, } } +static void outliner_mode_toggle_fn(bContext *C, void *tselem_poin, void *UNUSED(arg2)) +{ + SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); + TreeStoreElem *tselem = (TreeStoreElem *)tselem_poin; + TreeViewContext tvc; + outliner_viewcontext_init(C, &tvc); + + TreeElement *te = outliner_find_tree_element(&space_outliner->tree, tselem); + if (!te) { + return; + } + + outliner_item_mode_toggle(C, &tvc, te); +} + +/* Return the icon for a given interaction mode + * Should this be more generic (in a different file?) */ +static int outliner_get_mode_icon(const int mode) +{ + switch (mode) { + case OB_MODE_OBJECT: + return ICON_OBJECT_DATAMODE; + case OB_MODE_EDIT: + case OB_MODE_EDIT_GPENCIL: + return ICON_EDITMODE_HLT; + case OB_MODE_SCULPT: + case OB_MODE_SCULPT_GPENCIL: + return ICON_SCULPTMODE_HLT; + case OB_MODE_VERTEX_PAINT: + case OB_MODE_VERTEX_GPENCIL: + return ICON_VPAINT_HLT; + case OB_MODE_WEIGHT_PAINT: + case OB_MODE_WEIGHT_GPENCIL: + return ICON_WPAINT_HLT; + case OB_MODE_TEXTURE_PAINT: + return ICON_TPAINT_HLT; + case OB_MODE_PARTICLE_EDIT: + return ICON_PARTICLEMODE; + case OB_MODE_POSE: + return ICON_POSE_HLT; + case OB_MODE_PAINT_GPENCIL: + return ICON_GREASEPENCIL; + default: + return ICON_DOT; + } +} + +/* Draw icons for adding and removing objects from the current interation mode */ +static void outliner_draw_mode_column_toggle(uiBlock *block, + TreeViewContext *tvc, + TreeElement *te, + TreeStoreElem *tselem, + const bool lock_object_modes) +{ + uiBut *but; + const int active_mode = tvc->obact->mode; + bool draw_active_icon = true; + + if (tselem->type == 0 && te->idcode == ID_OB) { + Object *ob = (Object *)tselem->id; + + /* When not locking object modes, objects can remain in non-object modes. For modes that do not + * allow multi-object editing, these other objects should still show be viewed as not in the + * mode. Otherwise multiple objects show the same mode icon in the outliner even though only + * one object is actually editable in the mode. */ + if (!lock_object_modes && ob != tvc->obact && !(tvc->ob_edit || tvc->ob_pose)) { + draw_active_icon = false; + } + + if (ob->type == tvc->obact->type) { + if (draw_active_icon && ob->mode == tvc->obact->mode) { + but = uiDefIconBut(block, + UI_BTYPE_ICON_TOGGLE, + 0, + outliner_get_mode_icon(active_mode), + 0, + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0.0, + 0.0, + 0.0, + 0.0, + TIP_("Remove from the current mode")); + UI_but_func_set(but, outliner_mode_toggle_fn, tselem, NULL); + UI_but_flag_enable(but, UI_BUT_DRAG_LOCK); + } + else { + /* Not all objects have particle systems */ + if (active_mode == OB_MODE_PARTICLE_EDIT && !psys_get_current(ob)) { + return; + } + but = uiDefIconBut(block, + UI_BTYPE_ICON_TOGGLE, + 0, + tselem->flag & TSE_HIGHLIGHTED ? outliner_get_mode_icon(active_mode) : + ICON_DOT, + 0, + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0.0, + 0.0, + 0.0, + 0.0, + TIP_("Add to the current mode")); + UI_but_func_set(but, outliner_mode_toggle_fn, tselem, NULL); + UI_but_flag_enable(but, UI_BUT_DRAG_LOCK); + } + } + } +} + +static void outliner_draw_mode_column(const bContext *C, + uiBlock *block, + TreeViewContext *tvc, + SpaceOutliner *space_outliner, + ListBase *tree) +{ + TreeStoreElem *tselem; + const bool lock_object_modes = tvc->scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK; + + LISTBASE_FOREACH (TreeElement *, te, tree) { + tselem = TREESTORE(te); + + if (tvc->obact && tvc->obact->mode != OB_MODE_OBJECT) { + outliner_draw_mode_column_toggle(block, tvc, te, tselem, lock_object_modes); + } + + if (TSELEM_OPEN(tselem, space_outliner)) { + outliner_draw_mode_column(C, block, tvc, space_outliner, &te->subtree); + } + } +} + /* ****************************************************** */ /* Normal Drawing... */ @@ -1939,9 +2077,11 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) break; case TSE_CONSTRAINT_BASE: data.icon = ICON_CONSTRAINT; + data.drag_id = tselem->id; break; case TSE_CONSTRAINT: { bConstraint *con = te->directdata; + data.drag_id = tselem->id; switch ((eBConstraint_Types)con->type) { case CONSTRAINT_TYPE_CAMERASOLVER: data.icon = ICON_CON_CAMERASOLVER; @@ -2036,6 +2176,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) } case TSE_MODIFIER_BASE: data.icon = ICON_MODIFIER_DATA; + data.drag_id = tselem->id; break; case TSE_LINKED_OB: data.icon = ICON_OBJECT_DATA; @@ -2045,6 +2186,8 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) break; case TSE_MODIFIER: { Object *ob = (Object *)tselem->id; + data.drag_id = tselem->id; + if (ob->type != OB_GPENCIL) { ModifierData *md = BLI_findlink(&ob->modifiers, tselem->nr); switch ((ModifierType)md->type) { @@ -2211,7 +2354,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) GpencilModifierData *md = BLI_findlink(&ob->greasepencil_modifiers, tselem->nr); switch ((GpencilModifierType)md->type) { case eGpencilModifierType_Noise: - data.icon = ICON_RNDCURVE; + data.icon = ICON_MOD_NOISE; break; case eGpencilModifierType_Subdiv: data.icon = ICON_MOD_SUBSURF; @@ -2255,6 +2398,15 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) case eGpencilModifierType_Armature: data.icon = ICON_MOD_ARMATURE; break; + case eGpencilModifierType_Multiply: + data.icon = ICON_GP_MULTIFRAME_EDITING; + break; + case eGpencilModifierType_Time: + data.icon = ICON_MOD_TIME; + break; + case eGpencilModifierType_Texture: + data.icon = ICON_TEXTURE; + break; /* Default */ default: @@ -2377,6 +2529,11 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) data.icon = ICON_OUTLINER_DATA_GP_LAYER; break; } + case TSE_EFFECT_BASE: + case TSE_EFFECT: + data.drag_id = tselem->id; + data.icon = ICON_SHADERFX; + break; default: data.icon = ICON_DOT; break; @@ -2723,15 +2880,38 @@ static void outliner_draw_iconrow_number(const uiFontStyle *fstyle, GPU_blend(GPU_BLEND_ALPHA); /* Roundbox and text drawing disables. */ } -static void outliner_icon_background_colors(float icon_color[4], float icon_border[4]) +static void outliner_draw_active_highlight(const float minx, + const float miny, + const float maxx, + const float maxy) +{ + const float ufac = U.pixelsize; + float icon_border[4]; + UI_GetThemeColor4fv(TH_TEXT, icon_border); + icon_border[3] = 0.6f; + + /* border around it */ + UI_draw_roundbox_corner_set(UI_CNR_ALL); + UI_draw_roundbox_aa( + false, minx + ufac, miny + ufac, maxx - ufac, maxy - ufac, UI_UNIT_Y / 4.0f, icon_border); + GPU_blend(true); /* Roundbox disables. */ +} + +/* Draw a rounded rectangle behind icons of active elements. */ +static void outliner_draw_active_indicator(const float minx, + const float miny, + const float maxx, + const float maxy, + const float icon_color[4], + const float icon_border[4]) { - float text[4]; - UI_GetThemeColor4fv(TH_TEXT, text); + const float ufac = UI_UNIT_X / 20.0f; + const float radius = UI_UNIT_Y / 4.0f; - copy_v3_v3(icon_color, text); - icon_color[3] = 0.4f; - copy_v3_v3(icon_border, text); - icon_border[3] = 0.2f; + UI_draw_roundbox_corner_set(UI_CNR_ALL); + UI_draw_roundbox_aa(true, minx, miny + ufac, maxx, maxy - ufac, radius, icon_color); + UI_draw_roundbox_aa(false, minx, miny + ufac, maxx, maxy - ufac, radius, icon_border); + GPU_blend(GPU_BLEND_ALPHA); /* Roundbox disables. */ } static void outliner_draw_iconrow_doit(uiBlock *block, @@ -2747,31 +2927,8 @@ static void outliner_draw_iconrow_doit(uiBlock *block, TreeStoreElem *tselem = TREESTORE(te); if (active != OL_DRAWSEL_NONE) { - float ufac = UI_UNIT_X / 20.0f; - float icon_color[4], icon_border[4]; - outliner_icon_background_colors(icon_color, icon_border); - if (active == OL_DRAWSEL_ACTIVE) { - UI_GetThemeColor4fv(TH_EDITED_OBJECT, icon_color); - icon_border[3] = 0.3f; - } - UI_draw_roundbox_corner_set(UI_CNR_ALL); - - UI_draw_roundbox_aa(true, - (float)*offsx, - (float)ys + ufac, - (float)*offsx + UI_UNIT_X, - (float)ys + UI_UNIT_Y - ufac, - (float)UI_UNIT_Y / 4.0f, - icon_color); - /* border around it */ - UI_draw_roundbox_aa(false, - (float)*offsx, - (float)ys + ufac, - (float)*offsx + UI_UNIT_X, - (float)ys + UI_UNIT_Y - ufac, - (float)UI_UNIT_Y / 4.0f, - icon_border); - GPU_blend(GPU_BLEND_ALPHA); /* Roundbox disables. */ + outliner_draw_active_highlight( + (float)*offsx, (float)ys, (float)*offsx + UI_UNIT_X, (float)ys + UI_UNIT_Y); } if (tselem->flag & TSE_HIGHLIGHTED) { @@ -2953,8 +3110,6 @@ static void outliner_draw_tree_element(bContext *C, eOLDrawState active = OL_DRAWSEL_NONE; uchar text_color[4]; UI_GetThemeColor4ubv(TH_TEXT, text_color); - float icon_bgcolor[4], icon_border[4]; - outliner_icon_background_colors(icon_bgcolor, icon_border); if (*starty + 2 * UI_UNIT_Y >= region->v2d.cur.ymin && *starty <= region->v2d.cur.ymax) { const float alpha_fac = ((te->flag & TE_DISABLED) || (te->flag & TE_CHILD_NOT_IN_COLLECTION) || @@ -2979,7 +3134,6 @@ static void outliner_draw_tree_element(bContext *C, if (te->idcode == ID_SCE) { if (tselem->id == (ID *)tvc->scene) { /* active scene */ - icon_bgcolor[3] = 0.2f; active = OL_DRAWSEL_ACTIVE; } } @@ -3008,14 +3162,11 @@ static void outliner_draw_tree_element(bContext *C, } else if (is_object_data_in_editmode(tselem->id, tvc->obact)) { /* objects being edited */ - UI_GetThemeColor4fv(TH_EDITED_OBJECT, icon_bgcolor); - icon_border[3] = 0.3f; active = OL_DRAWSEL_ACTIVE; } else { if (tree_element_active(C, tvc, space_outliner, te, OL_SETSEL_NONE, false)) { /* active items like camera or material */ - icon_bgcolor[3] = 0.2f; active = OL_DRAWSEL_ACTIVE; } } @@ -3023,7 +3174,6 @@ static void outliner_draw_tree_element(bContext *C, else if (tselem->type == TSE_GP_LAYER) { /* Active grease pencil layer. */ if (((bGPDlayer *)te->directdata)->flag & GP_LAYER_ACTIVE) { - icon_bgcolor[3] = 0.2f; active = OL_DRAWSEL_ACTIVE; } } @@ -3034,23 +3184,10 @@ static void outliner_draw_tree_element(bContext *C, /* active circle */ if (active != OL_DRAWSEL_NONE) { - UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_aa(true, - (float)startx + offsx + UI_UNIT_X, - (float)*starty + ufac, - (float)startx + offsx + 2.0f * UI_UNIT_X, - (float)*starty + UI_UNIT_Y - ufac, - UI_UNIT_Y / 4.0f, - icon_bgcolor); - /* border around it */ - UI_draw_roundbox_aa(false, - (float)startx + offsx + UI_UNIT_X, - (float)*starty + ufac, - (float)startx + offsx + 2.0f * UI_UNIT_X, - (float)*starty + UI_UNIT_Y - ufac, - UI_UNIT_Y / 4.0f, - icon_border); - GPU_blend(GPU_BLEND_ALPHA); /* roundbox disables it */ + outliner_draw_active_highlight((float)startx + offsx + UI_UNIT_X, + (float)*starty, + (float)startx + offsx + 2.0f * UI_UNIT_X, + (float)*starty + UI_UNIT_Y); te->flag |= TE_ACTIVE; /* For lookup in display hierarchies. */ } @@ -3113,7 +3250,8 @@ static void outliner_draw_tree_element(bContext *C, offsx += (int)(UI_UNIT_X + UI_fontstyle_string_width(fstyle, te->name)); /* closed item, we draw the icons, not when it's a scene, or master-server list though */ - if (!TSELEM_OPEN(tselem, space_outliner)) { + if (!TSELEM_OPEN(tselem, space_outliner) && + !(space_outliner->filter & SO_FILTER_NO_ROW_CHILDREN)) { if (te->subtree.first) { if (tselem->type == 0 && te->idcode == ID_SCE) { /* pass */ @@ -3305,8 +3443,20 @@ static void outliner_draw_struct_marks(ARegion *region, } } -static void outliner_draw_highlights_recursive(uint pos, - const ARegion *region, +static void draw_line_highlight(int x, int y, int maxx, int maxy, const float color[4]) +{ + const float pad = U.pixelsize; + UI_draw_roundbox_corner_set(UI_CNR_ALL); + UI_draw_roundbox_aa(true, + (float)x + pad, + (float)y + pad, + (float)maxx - (pad * 2), /* Extra offset needed on right. */ + (float)maxy - pad, + 5.0f, + color); +} + +static void outliner_draw_highlights_recursive(const ARegion *region, const SpaceOutliner *space_outliner, const ListBase *lb, const float col_selection[4], @@ -3323,20 +3473,19 @@ static void outliner_draw_highlights_recursive(uint pos, LISTBASE_FOREACH (TreeElement *, te, lb) { const TreeStoreElem *tselem = TREESTORE(te); const int start_y = *io_start_y; + const int end_x = (int)region->v2d.cur.xmax; /* selection status */ if ((tselem->flag & TSE_ACTIVE) && (tselem->flag & TSE_SELECTED)) { - immUniformColor4fv(col_active); - immRecti(pos, 0, start_y, (int)region->v2d.cur.xmax, start_y + UI_UNIT_Y); + draw_line_highlight(0, start_y, (int)region->v2d.cur.xmax, start_y + UI_UNIT_Y, col_active); } else if (tselem->flag & TSE_SELECTED) { - immUniformColor4fv(col_selection); - immRecti(pos, 0, start_y, (int)region->v2d.cur.xmax, start_y + UI_UNIT_Y); + draw_line_highlight( + 0, start_y, (int)region->v2d.cur.xmax, start_y + UI_UNIT_Y, col_selection); } /* highlights */ if (tselem->flag & (TSE_DRAG_ANY | TSE_HIGHLIGHTED | TSE_SEARCHMATCH)) { - const int end_x = (int)region->v2d.cur.xmax; if (tselem->flag & TSE_DRAG_ANY) { /* drag and drop highlight */ @@ -3344,20 +3493,18 @@ static void outliner_draw_highlights_recursive(uint pos, UI_GetThemeColorShade4fv(TH_BACK, -40, col); if (tselem->flag & TSE_DRAG_BEFORE) { - immUniformColor4fv(col); - immRecti(pos, - start_x, - start_y + UI_UNIT_Y - U.pixelsize, - end_x, - start_y + UI_UNIT_Y + U.pixelsize); + draw_line_highlight(start_x, + start_y + UI_UNIT_Y - (U.pixelsize * 2), + end_x, + start_y + UI_UNIT_Y + (U.pixelsize * 2), + col); } else if (tselem->flag & TSE_DRAG_AFTER) { - immUniformColor4fv(col); - immRecti(pos, start_x, start_y - U.pixelsize, end_x, start_y + U.pixelsize); + draw_line_highlight( + start_x, start_y - (U.pixelsize * 2), end_x, start_y + (U.pixelsize * 2), col); } else { - immUniformColor3fvAlpha(col, col[3] * 0.5f); - immRecti(pos, start_x, start_y, end_x, start_y + UI_UNIT_Y); + draw_line_highlight(start_x, start_y, end_x, start_y + UI_UNIT_Y, col); } } else { @@ -3365,21 +3512,18 @@ static void outliner_draw_highlights_recursive(uint pos, /* search match highlights * we don't expand items when searching in the data-blocks but we * still want to highlight any filter matches. */ - immUniformColor4fv(col_searchmatch); - immRecti(pos, start_x, start_y, end_x, start_y + UI_UNIT_Y); + draw_line_highlight(start_x, start_y, end_x, start_y + UI_UNIT_Y, col_searchmatch); } else if (tselem->flag & TSE_HIGHLIGHTED) { /* mouse hover highlight */ - immUniformColor4fv(col_highlight); - immRecti(pos, 0, start_y, end_x, start_y + UI_UNIT_Y); + draw_line_highlight(0, start_y, end_x, start_y + UI_UNIT_Y, col_highlight); } } } *io_start_y -= UI_UNIT_Y; if (TSELEM_OPEN(tselem, space_outliner)) { - outliner_draw_highlights_recursive(pos, - region, + outliner_draw_highlights_recursive(region, space_outliner, &te->subtree, col_selection, @@ -3389,6 +3533,10 @@ static void outliner_draw_highlights_recursive(uint pos, start_x + UI_UNIT_X, io_start_y); } + else if (outliner_find_element_with_flag(&te->subtree, TSE_ACTIVE)) { + /* Parent highlight for active element in collapsed subtree. */ + draw_line_highlight(0, start_y, end_x, start_y + UI_UNIT_Y, col_highlight); + } } } @@ -3400,19 +3548,12 @@ static void outliner_draw_highlights(ARegion *region, const float col_highlight[4] = {1.0f, 1.0f, 1.0f, 0.13f}; float col_selection[4], col_active[4], col_searchmatch[4]; - UI_GetThemeColor3fv(TH_SELECT_HIGHLIGHT, col_selection); - col_selection[3] = 1.0f; /* no alpha */ - UI_GetThemeColor3fv(TH_SELECT_ACTIVE, col_active); - col_active[3] = 1.0f; /* no alpha */ + UI_GetThemeColor4fv(TH_SELECT_HIGHLIGHT, col_selection); + UI_GetThemeColor4fv(TH_SELECT_ACTIVE, col_active); UI_GetThemeColor4fv(TH_MATCH, col_searchmatch); col_searchmatch[3] = 0.5f; - GPU_blend(GPU_BLEND_ALPHA); - GPUVertFormat *format = immVertexFormat(); - uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - outliner_draw_highlights_recursive(pos, - region, + outliner_draw_highlights_recursive(region, space_outliner, &space_outliner->tree, col_selection, @@ -3421,8 +3562,6 @@ static void outliner_draw_highlights(ARegion *region, col_searchmatch, startx, starty); - immUnbindProgram(); - GPU_blend(GPU_BLEND_NONE); } static void outliner_draw_tree(bContext *C, @@ -3431,11 +3570,20 @@ static void outliner_draw_tree(bContext *C, ARegion *region, SpaceOutliner *space_outliner, const float restrict_column_width, + const bool use_mode_column, TreeElement **te_edit) { const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; int starty, startx; + /* Move the tree a unit left in view layer mode */ + short mode_column_offset = (use_mode_column && (space_outliner->outlinevis == SO_SCENES)) ? + UI_UNIT_X : + 0; + if (!use_mode_column && (space_outliner->outlinevis == SO_VIEW_LAYER)) { + mode_column_offset -= UI_UNIT_X; + } + GPU_blend(GPU_BLEND_ALPHA); /* Only once. */ if (space_outliner->outlinevis == SO_DATA_API) { @@ -3461,12 +3609,12 @@ static void outliner_draw_tree(bContext *C, /* Gray hierarchy lines. */ starty = (int)region->v2d.tot.ymax - OL_Y_OFFSET; - startx = UI_UNIT_X / 2 - (U.pixelsize + 1) / 2; + startx = mode_column_offset + UI_UNIT_X / 2 - (U.pixelsize + 1) / 2; outliner_draw_hierarchy_lines(space_outliner, &space_outliner->tree, startx, &starty); /* Items themselves. */ starty = (int)region->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET; - startx = 0; + startx = mode_column_offset; LISTBASE_FOREACH (TreeElement *, te, &space_outliner->tree) { outliner_draw_tree_element(C, block, @@ -3589,12 +3737,22 @@ void draw_outliner(const bContext *C) /* set matrix for 2d-view controls */ UI_view2d_view_ortho(v2d); + /* Only show mode column in View Layers and Scenes view */ + const bool use_mode_column = (space_outliner->flag & SO_MODE_COLUMN) && + (ELEM(space_outliner->outlinevis, SO_VIEW_LAYER, SO_SCENES)); + /* draw outliner stuff (background, hierarchy lines and names) */ const float restrict_column_width = outliner_restrict_columns_width(space_outliner); outliner_back(region); block = UI_block_begin(C, region, __func__, UI_EMBOSS); - outliner_draw_tree( - (bContext *)C, block, &tvc, region, space_outliner, restrict_column_width, &te_edit); + outliner_draw_tree((bContext *)C, + block, + &tvc, + region, + space_outliner, + restrict_column_width, + use_mode_column, + &te_edit); /* Compute outliner dimensions after it has been drawn. */ int tree_width, tree_height; @@ -3629,6 +3787,11 @@ void draw_outliner(const bContext *C) props_active); } + /* Draw mode icons */ + if (use_mode_column) { + outliner_draw_mode_column(C, block, &tvc, space_outliner, &space_outliner->tree); + } + UI_block_emboss_set(block, UI_EMBOSS); /* Draw edit buttons if necessary. */ diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index cd2fcd8e2cf..9fe29268603 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -285,61 +285,6 @@ void OUTLINER_OT_item_openclose(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Object Mode Enter/Exit Utilities - * \{ */ - -static void item_object_mode_enter_exit(bContext *C, ReportList *reports, Object *ob, bool enter) -{ - ViewLayer *view_layer = CTX_data_view_layer(C); - Object *obact = OBACT(view_layer); - - if ((ob->type != obact->type) || ID_IS_LINKED(ob->data)) { - return; - } - if (((ob->mode & obact->mode) != 0) == enter) { - return; - } - - if (ob == obact) { - BKE_report(reports, RPT_WARNING, "Active object mode not changed"); - return; - } - - Base *base = BKE_view_layer_base_find(view_layer, ob); - if (base == NULL) { - return; - } - Scene *scene = CTX_data_scene(C); - outliner_object_mode_toggle(C, scene, view_layer, base); -} - -void item_object_mode_enter_fn(bContext *C, - ReportList *reports, - Scene *UNUSED(scene), - TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), - TreeStoreElem *tselem, - void *UNUSED(user_data)) -{ - Object *ob = (Object *)tselem->id; - item_object_mode_enter_exit(C, reports, ob, true); -} - -void item_object_mode_exit_fn(bContext *C, - ReportList *reports, - Scene *UNUSED(scene), - TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), - TreeStoreElem *tselem, - void *UNUSED(user_data)) -{ - Object *ob = (Object *)tselem->id; - item_object_mode_enter_exit(C, reports, ob, false); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ /** \name Rename Operator * \{ */ diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index ad8f8a92b5f..ffb8e5001a7 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -222,7 +222,6 @@ typedef enum TreeItemSelectAction { OL_ITEM_ACTIVATE = (1 << 2), /* Activate the item */ OL_ITEM_EXTEND = (1 << 3), /* Extend the current selection */ OL_ITEM_RECURSIVE = (1 << 4), /* Select recursively */ - OL_ITEM_TOGGLE_MODE = (1 << 5) /* Temporary */ } TreeItemSelectAction; /* outliner_tree.c ----------------------------------------------- */ @@ -277,18 +276,18 @@ eOLDrawState tree_element_active(struct bContext *C, const eOLSetState set, const bool handle_all_types); +struct bPoseChannel *outliner_find_parent_bone(TreeElement *te, TreeElement **r_bone_te); + void outliner_item_select(struct bContext *C, struct SpaceOutliner *space_outliner, struct TreeElement *te, const short select_flag); -void outliner_object_mode_toggle(struct bContext *C, - Scene *scene, - ViewLayer *view_layer, - Base *base); - bool outliner_item_is_co_over_name_icons(const TreeElement *te, float view_co_x); bool outliner_item_is_co_within_close_toggle(const TreeElement *te, float view_co_x); +bool outliner_is_co_within_mode_column(SpaceOutliner *space_outliner, const float view_mval[2]); + +void outliner_item_mode_toggle(struct bContext *C, TreeViewContext *tvc, TreeElement *te); /* outliner_edit.c ---------------------------------------------- */ typedef void (*outliner_operation_fn)(struct bContext *C, @@ -384,6 +383,7 @@ void OUTLINER_OT_parent_drop(struct wmOperatorType *ot); void OUTLINER_OT_parent_clear(struct wmOperatorType *ot); void OUTLINER_OT_scene_drop(struct wmOperatorType *ot); void OUTLINER_OT_material_drop(struct wmOperatorType *ot); +void OUTLINER_OT_uistack_drop(struct wmOperatorType *ot); void OUTLINER_OT_collection_drop(struct wmOperatorType *ot); /* ...................................................... */ diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index 22541a0ab1f..15c6db265bb 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -88,6 +88,7 @@ void outliner_operatortypes(void) WM_operatortype_append(OUTLINER_OT_parent_clear); WM_operatortype_append(OUTLINER_OT_scene_drop); WM_operatortype_append(OUTLINER_OT_material_drop); + WM_operatortype_append(OUTLINER_OT_uistack_drop); WM_operatortype_append(OUTLINER_OT_collection_drop); /* collections */ diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index 1ac1b46f0d1..7249fbb5a28 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -27,12 +27,16 @@ #include "DNA_armature_types.h" #include "DNA_collection_types.h" +#include "DNA_constraint_types.h" +#include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" #include "DNA_light_types.h" #include "DNA_material_types.h" +#include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_sequence_types.h" +#include "DNA_shader_fx_types.h" #include "DNA_world_types.h" #include "BLI_listbase.h" @@ -46,6 +50,7 @@ #include "BKE_main.h" #include "BKE_object.h" #include "BKE_paint.h" +#include "BKE_particle.h" #include "BKE_scene.h" #include "BKE_sequencer.h" #include "BKE_workspace.h" @@ -54,6 +59,7 @@ #include "DEG_depsgraph_build.h" #include "ED_armature.h" +#include "ED_buttons.h" #include "ED_gpencil.h" #include "ED_object.h" #include "ED_outliner.h" @@ -73,183 +79,137 @@ #include "outliner_intern.h" -static bool do_outliner_activate_common(bContext *C, - Main *bmain, - Depsgraph *depsgraph, - Scene *scene, - ViewLayer *view_layer, - Base *base, - const bool extend, - const bool do_exit) +/** + * Find a new active object to keep the other objects in the mode. + * + * Identify other objects in the tree that are also in the interaction mode + * and set the next (circular) as the active object. If none are found, then + * the mode should be exited. + */ +static bool outliner_set_new_active(bContext *C, ListBase *tree, Object *ob, int mode) { - bool use_all = false; + ViewLayer *view_layer = CTX_data_view_layer(C); - if (do_exit) { - FOREACH_OBJECT_BEGIN (view_layer, ob_iter) { - ED_object_mode_generic_exit(bmain, depsgraph, scene, ob_iter); + LISTBASE_FOREACH (TreeElement *, te, tree) { + TreeStoreElem *tselem = TREESTORE(te); + if (tselem->type == 0 && te->idcode == ID_OB) { + Object *ob_te = (Object *)tselem->id; + + /* If an object is found in the mode and not the current element. */ + if (ob_te->mode == mode && ob_te != ob) { + Base *base = BKE_view_layer_base_find(view_layer, ob_te); + ED_object_base_activate(C, base); + return true; + } } - FOREACH_OBJECT_END; - } - /* Just like clicking in the object changes the active object, - * clicking on the object data should change it as well. */ - ED_object_base_activate(C, base); - - if (extend) { - use_all = true; - } - else { - ED_object_base_deselect_all(view_layer, NULL, SEL_DESELECT); + if (outliner_set_new_active(C, &te->subtree, ob, mode)) { + return true; + } } - return use_all; + return false; } /** - * Bring the newly selected object into edit mode. + * Bring the newly selected object into edit mode and activate it. * - * If extend is used, we try to have the other compatible selected objects in the new mode as well. - * Otherwise only the new object will be active, selected and in the edit mode. + * If extend is used, we try to have the other compatible selected objects in the new mode as + * well. Otherwise only the new object will be active, selected and in the edit mode. */ -static void do_outliner_item_editmode_toggle( - bContext *C, Scene *scene, ViewLayer *view_layer, Base *base, const bool extend) +static void do_outliner_item_editmode_toggle(bContext *C, Scene *scene, Base *base) { Main *bmain = CTX_data_main(C); - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - Object *obact = OBACT(view_layer); Object *ob = base->object; - bool use_all = false; + bool ok = false; - if (obact == NULL) { - ED_object_base_activate(C, base); - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - obact = ob; - use_all = true; - } - else if (obact->data == ob->data) { - use_all = true; - } - else if (obact->mode == OB_MODE_OBJECT) { - use_all = do_outliner_activate_common( - C, bmain, depsgraph, scene, view_layer, base, extend, false); - } - else if ((ob->type != obact->type) || ((obact->mode & OB_MODE_EDIT) == 0) || - ((obact->mode & OB_MODE_POSE) && ELEM(OB_ARMATURE, ob->type, obact->type)) || !extend) { - use_all = do_outliner_activate_common( - C, bmain, depsgraph, scene, view_layer, base, extend, true); - } + if (BKE_object_is_in_editmode(ob)) { + SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); + outliner_set_new_active(C, &space_outliner->tree, ob, ob->mode); - if (use_all) { - WM_operator_name_call(C, "OBJECT_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL); + ok = ED_object_editmode_exit_ex(bmain, scene, ob, EM_FREEDATA); } else { - bool ok; - if (BKE_object_is_in_editmode(ob)) { - ok = ED_object_editmode_exit_ex(bmain, scene, ob, EM_FREEDATA); - } - else { - ok = ED_object_editmode_enter_ex(CTX_data_main(C), scene, ob, EM_NO_CONTEXT); - } - if (ok) { - ED_object_base_select(base, (ob->mode & OB_MODE_EDIT) ? BA_SELECT : BA_DESELECT); - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - } + ok = ED_object_editmode_enter_ex(CTX_data_main(C), scene, ob, EM_NO_CONTEXT); + } + if (ok) { + ED_object_base_select(base, (ob->mode & OB_MODE_EDIT) ? BA_SELECT : BA_DESELECT); + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); } } -static void do_outliner_item_posemode_toggle( - bContext *C, Scene *scene, ViewLayer *view_layer, Base *base, const bool extend) +static void do_outliner_item_posemode_toggle(bContext *C, Scene *scene, Base *base) { Main *bmain = CTX_data_main(C); - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - Object *obact = OBACT(view_layer); Object *ob = base->object; - bool use_all = false; - if (obact == NULL) { - ED_object_base_activate(C, base); - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - obact = ob; - use_all = true; - } - else if (obact->data == ob->data) { - use_all = true; - } - else if (obact->mode == OB_MODE_OBJECT) { - use_all = do_outliner_activate_common( - C, bmain, depsgraph, scene, view_layer, base, extend, false); - } - else if ((!ELEM(ob->type, obact->type)) || - ((obact->mode & OB_MODE_EDIT) && ELEM(OB_ARMATURE, ob->type, obact->type))) { - use_all = do_outliner_activate_common( - C, bmain, depsgraph, scene, view_layer, base, extend, true); - } + bool ok = false; + if (ob->mode & OB_MODE_POSE) { + SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); + outliner_set_new_active(C, &space_outliner->tree, ob, ob->mode); - if (use_all) { - WM_operator_name_call(C, "OBJECT_OT_posemode_toggle", WM_OP_INVOKE_REGION_WIN, NULL); + ok = ED_object_posemode_exit_ex(bmain, ob); } else { - bool ok = false; - if (ob->mode & OB_MODE_POSE) { - ok = ED_object_posemode_exit_ex(bmain, ob); - } - else { - ok = ED_object_posemode_enter_ex(bmain, ob); - } - if (ok) { - ED_object_base_select(base, (ob->mode & OB_MODE_POSE) ? BA_SELECT : BA_DESELECT); - - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - } + ok = ED_object_posemode_enter_ex(bmain, ob); + ED_object_base_activate(C, base); + } + if (ok) { + ED_object_base_select(base, (ob->mode & OB_MODE_POSE) ? BA_SELECT : BA_DESELECT); + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); } } -/* For draw callback to run mode switching */ -void outliner_object_mode_toggle(bContext *C, Scene *scene, ViewLayer *view_layer, Base *base) +/* Toggle interaction mode for modes that do not allow multi-object editing */ +static void do_outliner_item_mode_toggle_generic(bContext *C, TreeViewContext *tvc, Base *base) { - Object *obact = OBACT(view_layer); - if (obact->mode & OB_MODE_EDIT) { - do_outliner_item_editmode_toggle(C, scene, view_layer, base, true); + Main *bmain = CTX_data_main(C); + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + const int active_mode = tvc->obact->mode; + + /* Remove the active object from the mode */ + if (tvc->scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) { + ED_object_mode_generic_exit(bmain, depsgraph, tvc->scene, tvc->obact); } - else if (obact->mode & OB_MODE_POSE) { - do_outliner_item_posemode_toggle(C, scene, view_layer, base, true); + + Base *base_old = BKE_view_layer_base_find(tvc->view_layer, tvc->obact); + if (base_old) { + ED_object_base_select(base_old, BA_DESELECT); } + ED_object_base_activate(C, base); + ED_object_base_select(base, BA_SELECT); + ED_object_mode_set(C, active_mode); + + ED_outliner_select_sync_from_object_tag(C); } /* Toggle the item's interaction mode if supported */ -static void outliner_item_mode_toggle(bContext *C, - TreeViewContext *tvc, - TreeElement *te, - const bool extend) +void outliner_item_mode_toggle(bContext *C, TreeViewContext *tvc, TreeElement *te) { TreeStoreElem *tselem = TREESTORE(te); - if (tselem->type == 0) { - if (OB_DATA_SUPPORT_EDITMODE(te->idcode)) { - Object *ob = (Object *)outliner_search_back(te, ID_OB); - if ((ob != NULL) && (ob->data == tselem->id)) { - Base *base = BKE_view_layer_base_find(tvc->view_layer, ob); - if ((base != NULL) && (base->flag & BASE_VISIBLE_DEPSGRAPH)) { - do_outliner_item_editmode_toggle(C, tvc->scene, tvc->view_layer, base, extend); - } - } - } - else if (ELEM(te->idcode, ID_GD)) { - /* set grease pencil to object mode */ - WM_operator_name_call(C, "GPENCIL_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL); - } - } - else if (tselem->type == TSE_POSE_BASE) { + if (tselem->type == 0 && te->idcode == ID_OB) { Object *ob = (Object *)tselem->id; Base *base = BKE_view_layer_base_find(tvc->view_layer, ob); - if (base != NULL) { - do_outliner_item_posemode_toggle(C, tvc->scene, tvc->view_layer, base, extend); + + if (!base || !(base->flag & BASE_VISIBLE_DEPSGRAPH)) { + return; + } + + if (tvc->ob_edit && OB_TYPE_SUPPORT_EDITMODE(ob->type)) { + do_outliner_item_editmode_toggle(C, tvc->scene, base); + } + else if (tvc->ob_pose && ob->type == OB_ARMATURE) { + do_outliner_item_posemode_toggle(C, tvc->scene, base); } + else { + do_outliner_item_mode_toggle_generic(C, tvc, base); + } + + ED_outliner_select_sync_from_object_tag(C); } } @@ -499,7 +459,7 @@ static eOLDrawState tree_element_active_material(bContext *C, return OL_DRAWSEL_NONE; } -static eOLDrawState tree_element_active_camera(bContext *C, +static eOLDrawState tree_element_active_camera(bContext *UNUSED(C), Scene *scene, ViewLayer *UNUSED(view_layer), TreeElement *te, @@ -508,16 +468,6 @@ static eOLDrawState tree_element_active_camera(bContext *C, Object *ob = (Object *)outliner_search_back(te, ID_OB); if (set != OL_SETSEL_NONE) { - scene->camera = ob; - - Main *bmain = CTX_data_main(C); - wmWindowManager *wm = bmain->wm.first; - - WM_windows_scene_data_sync(&wm->windows, scene); - DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); - DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_SCENE | NA_EDITED, NULL); - return OL_DRAWSEL_NONE; } return scene->camera == ob; @@ -858,15 +808,26 @@ static eOLDrawState tree_element_active_psys(bContext *C, } static int tree_element_active_constraint(bContext *C, - Scene *UNUSED(scene), - ViewLayer *UNUSED(sl), - TreeElement *UNUSED(te), + Scene *scene, + ViewLayer *view_layer, + TreeElement *te, TreeStoreElem *tselem, const eOLSetState set) { if (set != OL_SETSEL_NONE) { Object *ob = (Object *)tselem->id; + /* Activate the parent bone if this is a bone constraint. */ + te = te->parent; + while (te) { + tselem = TREESTORE(te); + if (tselem->type == TSE_POSE_CHANNEL) { + tree_element_active_posechannel(C, scene, view_layer, ob, te, tselem, set, false); + return OL_DRAWSEL_NONE; + } + te = te->parent; + } + WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); } @@ -1094,6 +1055,7 @@ eOLDrawState tree_element_type_active(bContext *C, case TSE_POSE_CHANNEL: return tree_element_active_posechannel( C, tvc->scene, tvc->view_layer, tvc->ob_pose, te, tselem, set, recursive); + case TSE_CONSTRAINT_BASE: case TSE_CONSTRAINT: return tree_element_active_constraint(C, tvc->scene, tvc->view_layer, te, tselem, set); case TSE_R_LAYER: @@ -1117,6 +1079,188 @@ eOLDrawState tree_element_type_active(bContext *C, return OL_DRAWSEL_NONE; } +bPoseChannel *outliner_find_parent_bone(TreeElement *te, TreeElement **r_bone_te) +{ + TreeStoreElem *tselem; + + te = te->parent; + while (te) { + tselem = TREESTORE(te); + if (tselem->type == TSE_POSE_CHANNEL) { + *r_bone_te = te; + return (bPoseChannel *)te->directdata; + } + te = te->parent; + } + + return NULL; +} + +static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreElem *tselem) +{ + PointerRNA ptr; + + /* ID Types */ + if (tselem->type == 0) { + RNA_id_pointer_create(tselem->id, &ptr); + + switch (te->idcode) { + case ID_SCE: + ED_buttons_set_context(C, &ptr, BCONTEXT_SCENE); + break; + case ID_OB: + ED_buttons_set_context(C, &ptr, BCONTEXT_OBJECT); + break; + case ID_ME: + case ID_CU: + case ID_MB: + case ID_IM: + case ID_LT: + case ID_LA: + case ID_CA: + case ID_KE: + case ID_SPK: + case ID_AR: + case ID_GD: + case ID_LP: + case ID_HA: + case ID_PT: + case ID_VO: + ED_buttons_set_context(C, &ptr, BCONTEXT_DATA); + break; + case ID_MA: + ED_buttons_set_context(C, &ptr, BCONTEXT_MATERIAL); + break; + case ID_WO: + ED_buttons_set_context(C, &ptr, BCONTEXT_WORLD); + break; + } + } + else { + switch (tselem->type) { + case TSE_DEFGROUP_BASE: + case TSE_DEFGROUP: + RNA_id_pointer_create(tselem->id, &ptr); + ED_buttons_set_context(C, &ptr, BCONTEXT_DATA); + break; + case TSE_CONSTRAINT_BASE: + case TSE_CONSTRAINT: { + TreeElement *bone_te = NULL; + bPoseChannel *pchan = outliner_find_parent_bone(te, &bone_te); + + if (pchan) { + RNA_pointer_create(TREESTORE(bone_te)->id, &RNA_PoseBone, pchan, &ptr); + ED_buttons_set_context(C, &ptr, BCONTEXT_BONE_CONSTRAINT); + } + else { + RNA_id_pointer_create(tselem->id, &ptr); + ED_buttons_set_context(C, &ptr, BCONTEXT_CONSTRAINT); + } + + /* Expand the selected constraint in the properties editor. */ + if (tselem->type != TSE_CONSTRAINT_BASE) { + bConstraint *con = te->directdata; + con->ui_expand_flag |= (1 << 0); + } + break; + } + case TSE_MODIFIER_BASE: + case TSE_MODIFIER: + RNA_id_pointer_create(tselem->id, &ptr); + ED_buttons_set_context(C, &ptr, BCONTEXT_MODIFIER); + + if (tselem->type != TSE_MODIFIER_BASE) { + Object *ob = (Object *)tselem->id; + + if (ob->type == OB_GPENCIL) { + GpencilModifierData *md = te->directdata; + md->ui_expand_flag |= (1 << 0); + } + else { + ModifierData *md = te->directdata; + md->ui_expand_flag |= (1 << 0); + } + } + + // PropertyRNA *prop = RNA_struct_type_find_property(&RNA_Modifier, "show_expanded"); + // RNA_property_boolean_set(&ptr, prop, true); + break; + case TSE_EFFECT_BASE: + case TSE_EFFECT: + RNA_id_pointer_create(tselem->id, &ptr); + ED_buttons_set_context(C, &ptr, BCONTEXT_SHADERFX); + + if (tselem->type != TSE_EFFECT_BASE) { + ShaderFxData *sfx = te->directdata; + sfx->ui_expand_flag |= (1 << 0); + } + break; + case TSE_BONE: { + bArmature *arm = (bArmature *)tselem->id; + Bone *bone = te->directdata; + + RNA_pointer_create(&arm->id, &RNA_Bone, bone, &ptr); + ED_buttons_set_context(C, &ptr, BCONTEXT_BONE); + break; + } + case TSE_EBONE: { + bArmature *arm = (bArmature *)tselem->id; + EditBone *ebone = te->directdata; + + RNA_pointer_create(&arm->id, &RNA_EditBone, ebone, &ptr); + ED_buttons_set_context(C, &ptr, BCONTEXT_BONE); + break; + } + case TSE_POSE_CHANNEL: { + Object *ob = (Object *)tselem->id; + bArmature *arm = ob->data; + bPoseChannel *pchan = te->directdata; + + RNA_pointer_create(&arm->id, &RNA_PoseBone, pchan, &ptr); + ED_buttons_set_context(C, &ptr, BCONTEXT_BONE); + break; + } + case TSE_POSE_BASE: { + Object *ob = (Object *)tselem->id; + bArmature *arm = ob->data; + + RNA_pointer_create(&arm->id, &RNA_Armature, arm, &ptr); + ED_buttons_set_context(C, &ptr, BCONTEXT_DATA); + break; + } + case TSE_R_LAYER_BASE: + case TSE_R_LAYER: { + ViewLayer *view_layer = te->directdata; + + RNA_pointer_create(tselem->id, &RNA_ViewLayer, view_layer, &ptr); + ED_buttons_set_context(C, &ptr, BCONTEXT_VIEW_LAYER); + break; + } + case TSE_POSEGRP_BASE: + case TSE_POSEGRP: { + Object *ob = (Object *)tselem->id; + bArmature *arm = ob->data; + + RNA_pointer_create(&arm->id, &RNA_Armature, arm, &ptr); + ED_buttons_set_context(C, &ptr, BCONTEXT_DATA); + break; + } + case TSE_LINKED_PSYS: { + Object *ob = (Object *)tselem->id; + ParticleSystem *psys = psys_get_current(ob); + + RNA_pointer_create(&ob->id, &RNA_ParticleSystem, psys, &ptr); + ED_buttons_set_context(C, &ptr, BCONTEXT_PARTICLE); + break; + } + case TSE_GP_LAYER: + RNA_id_pointer_create(tselem->id, &ptr); + ED_buttons_set_context(C, &ptr, BCONTEXT_DATA); + break; + } + } +} + /* ================================================ */ /** @@ -1141,14 +1285,8 @@ static void do_outliner_item_activate_tree_element(bContext *C, TSE_SEQUENCE_DUP, TSE_EBONE, TSE_LAYER_COLLECTION)) { - /* Note about TSE_EBONE: In case of a same ID_AR datablock shared among several objects, - * we do not want to switch out of edit mode (see T48328 for details). */ - } - else if (tselem->id && OB_DATA_SUPPORT_EDITMODE(te->idcode)) { - /* Support edit-mode toggle, keeping the active object as is. */ - } - else if (tselem->type == TSE_POSE_BASE) { - /* Support pose mode toggle, keeping the active object as is. */ + /* Note about TSE_EBONE: In case of a same ID_AR datablock shared among several + * objects, we do not want to switch out of edit mode (see T48328 for details). */ } else if (do_activate_data) { tree_element_set_active_object(C, @@ -1165,11 +1303,6 @@ static void do_outliner_item_activate_tree_element(bContext *C, if (do_activate_data == false) { /* Only select in outliner. */ } - else if (te->idcode == ID_SCE) { - if (tvc->scene != (Scene *)tselem->id) { - WM_window_set_active_scene(CTX_data_main(C), C, CTX_wm_window(C), (Scene *)tselem->id); - } - } else if ((te->idcode == ID_GR) && (space_outliner->outlinevis != SO_VIEW_LAYER)) { Collection *gr = (Collection *)tselem->id; @@ -1223,6 +1356,8 @@ static void do_outliner_item_activate_tree_element(bContext *C, extend ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL, recursive); } + + outliner_set_properties_tab(C, te, tselem); } /* Select the item using the set flags */ @@ -1236,7 +1371,8 @@ void outliner_item_select(bContext *C, const bool extend = select_flag & OL_ITEM_EXTEND; const bool activate_data = select_flag & OL_ITEM_SELECT_DATA; - /* Clear previous active when activating and clear selection when not extending selection */ + /* Clear previous active when activating and clear selection when not extending selection + */ const short clear_flag = (activate ? TSE_ACTIVE : 0) | (extend ? 0 : TSE_SELECTED); if (clear_flag) { outliner_flag_set(&space_outliner->tree, clear_flag, false); @@ -1262,11 +1398,6 @@ void outliner_item_select(bContext *C, extend, select_flag & OL_ITEM_RECURSIVE, activate_data || space_outliner->flag & SO_SYNC_SELECT); - - /* Mode toggle on data activate for now, but move later */ - if (select_flag & OL_ITEM_TOGGLE_MODE) { - outliner_item_mode_toggle(C, &tvc, te, extend); - } } } @@ -1327,7 +1458,8 @@ static void do_outliner_range_select(bContext *C, return; } - /* If active is not selected or visible, select and activate the element under the cursor */ + /* If active is not selected or visible, select and activate the element under the cursor + */ if (!active_selected || !outliner_is_element_visible(active)) { outliner_item_select(C, space_outliner, cursor, OL_ITEM_SELECT | OL_ITEM_ACTIVATE); return; @@ -1343,6 +1475,16 @@ static bool outliner_is_co_within_restrict_columns(const SpaceOutliner *space_ou return (view_co_x > region->v2d.cur.xmax - outliner_restrict_columns_width(space_outliner)); } +bool outliner_is_co_within_mode_column(SpaceOutliner *space_outliner, const float view_mval[2]) +{ + /* Mode toggles only show in View Layer and Scenes modes. */ + if (!ELEM(space_outliner->outlinevis, SO_VIEW_LAYER, SO_SCENES)) { + return false; + } + + return space_outliner->flag & SO_MODE_COLUMN && view_mval[0] < UI_UNIT_X; +} + /** * Action to run when clicking in the outliner, * @@ -1365,6 +1507,9 @@ static int outliner_item_do_activate_from_cursor(bContext *C, if (outliner_is_co_within_restrict_columns(space_outliner, region, view_mval[0])) { return OPERATOR_CANCELLED; } + else if (outliner_is_co_within_mode_column(space_outliner, view_mval)) { + return OPERATOR_CANCELLED; + } if (!(te = outliner_find_item_at_y(space_outliner, &space_outliner->tree, view_mval[1]))) { if (deselect_all) { @@ -1378,7 +1523,8 @@ static int outliner_item_do_activate_from_cursor(bContext *C, return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; } else { - /* The row may also contain children, if one is hovered we want this instead of current te. */ + /* The row may also contain children, if one is hovered we want this instead of current + * te. */ bool merged_elements = false; TreeElement *activate_te = outliner_find_item_at_x_in_row( space_outliner, te, view_mval[0], &merged_elements); @@ -1403,7 +1549,7 @@ static int outliner_item_do_activate_from_cursor(bContext *C, const short select_flag = OL_ITEM_ACTIVATE | (select ? OL_ITEM_SELECT : OL_ITEM_DESELECT) | (is_over_name_icons ? OL_ITEM_SELECT_DATA : 0) | - (extend ? OL_ITEM_EXTEND : 0) | OL_ITEM_TOGGLE_MODE; + (extend ? OL_ITEM_EXTEND : 0); outliner_item_select(C, space_outliner, activate_te, select_flag); } @@ -1532,6 +1678,10 @@ static int outliner_box_select_invoke(bContext *C, wmOperator *op, const wmEvent return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; } + if (outliner_is_co_within_mode_column(space_outliner, view_mval)) { + return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; + } + return WM_gesture_box_invoke(C, op, event); } @@ -1630,6 +1780,40 @@ static TreeElement *outliner_find_next_element(SpaceOutliner *space_outliner, Tr return te; } +static TreeElement *outliner_walk_left(SpaceOutliner *space_outliner, + TreeElement *te, + bool toggle_all) +{ + TreeStoreElem *tselem = TREESTORE(te); + + if (TSELEM_OPEN(tselem, space_outliner)) { + outliner_item_openclose(te, false, toggle_all); + } + /* Only walk up a level if the element is closed and not toggling expand */ + else if (!toggle_all && te->parent) { + te = te->parent; + } + + return te; +} + +static TreeElement *outliner_walk_right(SpaceOutliner *space_outliner, + TreeElement *te, + bool toggle_all) +{ + TreeStoreElem *tselem = TREESTORE(te); + + /* Only walk down a level if the element is open and not toggling expand */ + if (!toggle_all && TSELEM_OPEN(tselem, space_outliner) && te->subtree.first) { + te = te->subtree.first; + } + else { + outliner_item_openclose(te, true, toggle_all); + } + + return te; +} + static TreeElement *do_outliner_select_walk(SpaceOutliner *space_outliner, TreeElement *te, const int direction, @@ -1646,10 +1830,10 @@ static TreeElement *do_outliner_select_walk(SpaceOutliner *space_outliner, te = outliner_find_next_element(space_outliner, te); break; case UI_SELECT_WALK_LEFT: - outliner_item_openclose(te, false, toggle_all); + te = outliner_walk_left(space_outliner, te, toggle_all); break; case UI_SELECT_WALK_RIGHT: - outliner_item_openclose(te, true, toggle_all); + te = outliner_walk_right(space_outliner, te, toggle_all); break; } diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index 965e6d1177a..2394b4a07d6 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -95,110 +95,105 @@ /** \name ID/Library/Data Set/Un-link Utilities * \{ */ -static void set_operation_types(SpaceOutliner *space_outliner, - ListBase *lb, - int *scenelevel, - int *objectlevel, - int *idlevel, - int *datalevel) +static void get_element_operation_type( + TreeElement *te, int *scenelevel, int *objectlevel, int *idlevel, int *datalevel) { - TreeElement *te; - TreeStoreElem *tselem; + TreeStoreElem *tselem = TREESTORE(te); + if (tselem->flag & TSE_SELECTED) { + /* Layer collection points to collection ID. */ + if (!ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) { + if (*datalevel == 0) { + *datalevel = tselem->type; + } + else if (*datalevel != tselem->type) { + *datalevel = -1; + } + } + else { + const int idcode = (int)GS(tselem->id->name); + bool is_standard_id = false; + switch ((ID_Type)idcode) { + case ID_SCE: + *scenelevel = 1; + break; + case ID_OB: + *objectlevel = 1; + break; - for (te = lb->first; te; te = te->next) { - tselem = TREESTORE(te); - if (tselem->flag & TSE_SELECTED) { - /* Layer collection points to collection ID. */ - if (!ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) { - if (*datalevel == 0) { - *datalevel = tselem->type; - } - else if (*datalevel != tselem->type) { - *datalevel = -1; - } + case ID_ME: + case ID_CU: + case ID_MB: + case ID_LT: + case ID_LA: + case ID_AR: + case ID_CA: + case ID_SPK: + case ID_MA: + case ID_TE: + case ID_IP: + case ID_IM: + case ID_SO: + case ID_KE: + case ID_WO: + case ID_AC: + case ID_TXT: + case ID_GR: + case ID_LS: + case ID_LI: + case ID_VF: + case ID_NT: + case ID_BR: + case ID_PA: + case ID_GD: + case ID_MC: + case ID_MSK: + case ID_PAL: + case ID_PC: + case ID_CF: + case ID_WS: + case ID_LP: + case ID_HA: + case ID_PT: + case ID_VO: + case ID_SIM: + is_standard_id = true; + break; + case ID_WM: + case ID_SCR: + /* Those are ignored here. */ + /* Note: while Screens should be manageable here, deleting a screen used by a workspace + * will cause crashes when trying to use that workspace, so for now let's play minimal, + * safe change. */ + break; + } + if (idcode == ID_NLA) { + /* Fake one, not an actual ID type... */ + is_standard_id = true; } - else { - const int idcode = (int)GS(tselem->id->name); - bool is_standard_id = false; - switch ((ID_Type)idcode) { - case ID_SCE: - *scenelevel = 1; - break; - case ID_OB: - *objectlevel = 1; - break; - case ID_ME: - case ID_CU: - case ID_MB: - case ID_LT: - case ID_LA: - case ID_AR: - case ID_CA: - case ID_SPK: - case ID_MA: - case ID_TE: - case ID_IP: - case ID_IM: - case ID_SO: - case ID_KE: - case ID_WO: - case ID_AC: - case ID_TXT: - case ID_GR: - case ID_LS: - case ID_LI: - case ID_VF: - case ID_NT: - case ID_BR: - case ID_PA: - case ID_GD: - case ID_MC: - case ID_MSK: - case ID_PAL: - case ID_PC: - case ID_CF: - case ID_WS: - case ID_LP: - case ID_HA: - case ID_PT: - case ID_VO: - case ID_SIM: - is_standard_id = true; - break; - case ID_WM: - case ID_SCR: - /* Those are ignored here. */ - /* Note: while Screens should be manageable here, deleting a screen used by a workspace - * will cause crashes when trying to use that workspace, so for now let's play minimal, - * safe change. */ - break; + if (is_standard_id) { + if (*idlevel == 0) { + *idlevel = idcode; } - if (idcode == ID_NLA) { - /* Fake one, not an actual ID type... */ - is_standard_id = true; + else if (*idlevel != idcode) { + *idlevel = -1; } - - if (is_standard_id) { - if (*idlevel == 0) { - *idlevel = idcode; - } - else if (*idlevel != idcode) { - *idlevel = -1; - } - if (ELEM(*datalevel, TSE_VIEW_COLLECTION_BASE, TSE_SCENE_COLLECTION_BASE)) { - *datalevel = 0; - } + if (ELEM(*datalevel, TSE_VIEW_COLLECTION_BASE, TSE_SCENE_COLLECTION_BASE)) { + *datalevel = 0; } } } - if (TSELEM_OPEN(tselem, space_outliner)) { - set_operation_types( - space_outliner, &te->subtree, scenelevel, objectlevel, idlevel, datalevel); - } } } +static TreeElement *get_target_element(SpaceOutliner *space_outliner) +{ + TreeElement *te = outliner_find_element_with_flag(&space_outliner->tree, TSE_ACTIVE); + BLI_assert(te); + + return te; +} + static void unlink_action_fn(bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), @@ -405,7 +400,8 @@ static void outliner_do_libdata_operation(bContext *C, for (te = lb->first; te; te = te->next) { tselem = TREESTORE(te); if (tselem->flag & TSE_SELECTED) { - if (ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) { + /* TODO (Nathan): Why is TSE_LAYER_COLLECTION an exception here? */ + if ((tselem->type == 0 && te->idcode != 0) /* || tselem->type == TSE_LAYER_COLLECTION*/) { TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : NULL; operation_fn(C, reports, scene, te, tsep, tselem, user_data); } @@ -792,10 +788,11 @@ static void id_override_library_create_fn(bContext *C, } else if (ID_IS_OVERRIDABLE_LIBRARY(id_root)) { BKE_lib_override_library_create_from_id(bmain, id_root, true); - } - BKE_main_id_clear_newpoins(bmain); - BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); + /* Cleanup. */ + BKE_main_id_clear_newpoins(bmain); + BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); + } } } @@ -827,6 +824,68 @@ static void id_override_library_reset_fn(bContext *C, } } +static void id_override_library_resync_fn(bContext *C, + ReportList *UNUSED(reports), + Scene *scene, + TreeElement *te, + TreeStoreElem *UNUSED(tsep), + TreeStoreElem *tselem, + void *UNUSED(user_data)) +{ + BLI_assert(TSE_IS_REAL_ID(tselem)); + ID *id_root = tselem->id; + + if (ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) { + Main *bmain = CTX_data_main(C); + + id_root->tag |= LIB_TAG_DOIT; + + /* Tag all linked parents in tree hierarchy to be also overridden. */ + while ((te = te->parent) != NULL) { + if (!TSE_IS_REAL_ID(te->store_elem)) { + continue; + } + if (!ID_IS_OVERRIDE_LIBRARY_REAL(te->store_elem->id)) { + break; + } + te->store_elem->id->tag |= LIB_TAG_DOIT; + } + + BKE_lib_override_library_resync(bmain, scene, CTX_data_view_layer(C), id_root); + } +} + +static void id_override_library_delete_fn(bContext *C, + ReportList *UNUSED(reports), + Scene *UNUSED(scene), + TreeElement *te, + TreeStoreElem *UNUSED(tsep), + TreeStoreElem *tselem, + void *UNUSED(user_data)) +{ + BLI_assert(TSE_IS_REAL_ID(tselem)); + ID *id_root = tselem->id; + + if (ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) { + Main *bmain = CTX_data_main(C); + + id_root->tag |= LIB_TAG_DOIT; + + /* Tag all linked parents in tree hierarchy to be also overridden. */ + while ((te = te->parent) != NULL) { + if (!TSE_IS_REAL_ID(te->store_elem)) { + continue; + } + if (!ID_IS_OVERRIDE_LIBRARY_REAL(te->store_elem->id)) { + break; + } + te->store_elem->id->tag |= LIB_TAG_DOIT; + } + + BKE_lib_override_library_delete(bmain, id_root); + } +} + static void id_fake_user_set_fn(bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), @@ -1344,8 +1403,6 @@ enum { OL_OP_TOGSEL, OL_OP_TOGREN, OL_OP_RENAME, - OL_OP_OBJECT_MODE_ENTER, - OL_OP_OBJECT_MODE_EXIT, }; static const EnumPropertyItem prop_object_op_types[] = { @@ -1358,8 +1415,6 @@ static const EnumPropertyItem prop_object_op_types[] = { "Remap Users", "Make all users of selected data-blocks to use instead a new chosen one"}, {OL_OP_RENAME, "RENAME", 0, "Rename", ""}, - {OL_OP_OBJECT_MODE_ENTER, "OBJECT_MODE_ENTER", 0, "Enter Mode", ""}, - {OL_OP_OBJECT_MODE_EXIT, "OBJECT_MODE_EXIT", 0, "Exit Mode", ""}, {0, NULL, 0, NULL, NULL}, }; @@ -1429,16 +1484,6 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) C, op->reports, scene, space_outliner, &space_outliner->tree, item_rename_fn); str = "Rename Object"; } - else if (event == OL_OP_OBJECT_MODE_ENTER) { - outliner_do_object_operation( - C, op->reports, scene, space_outliner, &space_outliner->tree, item_object_mode_enter_fn); - str = "Enter Current Mode"; - } - else if (event == OL_OP_OBJECT_MODE_EXIT) { - outliner_do_object_operation( - C, op->reports, scene, space_outliner, &space_outliner->tree, item_object_mode_exit_fn); - str = "Exit Current Mode"; - } else { BLI_assert(0); return OPERATOR_CANCELLED; @@ -1607,6 +1652,8 @@ typedef enum eOutlinerIdOpTypes { OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY, OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET, OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET_HIERARCHY, + OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY, + OUTLINER_IDOP_OVERRIDE_LIBRARY_DELETE_HIERARCHY, OUTLINER_IDOP_SINGLE, OUTLINER_IDOP_DELETE, OUTLINER_IDOP_REMAP, @@ -1653,6 +1700,18 @@ static const EnumPropertyItem prop_id_op_types[] = { 0, "Reset Library Override Hierarchy", "Reset this local override to its linked values, as well as its hierarchy of dependencies"}, + {OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY, + "OVERRIDE_LIBRARY_RESYNC_HIERARCHY", + 0, + "Resync Library Override Hierarchy", + "Rebuild this local override from its linked reference, as well as its hierarchy of " + "dependencies"}, + {OUTLINER_IDOP_OVERRIDE_LIBRARY_DELETE_HIERARCHY, + "OVERRIDE_LIBRARY_DELETE_HIERARCHY", + 0, + "Delete Library Override Hierarchy", + "Delete this local override (including its hierarchy of override dependencies) and relink " + "its usages to the linked data-blocks"}, {0, "", 0, NULL, NULL}, {OUTLINER_IDOP_COPY, "COPY", ICON_COPYDOWN, "Copy", ""}, {OUTLINER_IDOP_PASTE, "PASTE", ICON_PASTEDOWN, "Paste", ""}, @@ -1683,6 +1742,10 @@ static bool outliner_id_operation_item_poll(bContext *C, case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET: case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET_HIERARCHY: return true; + case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY: + return true; + case OUTLINER_IDOP_OVERRIDE_LIBRARY_DELETE_HIERARCHY: + return true; case OUTLINER_IDOP_SINGLE: if (!space_outliner || ELEM(space_outliner->outlinevis, SO_SCENES, SO_VIEW_LAYER)) { return true; @@ -1724,18 +1787,16 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; - eOutlinerIdOpTypes event; /* check for invalid states */ if (space_outliner == NULL) { return OPERATOR_CANCELLED; } - set_operation_types( - space_outliner, &space_outliner->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); - - event = RNA_enum_get(op->ptr, "type"); + TreeElement *te = get_target_element(space_outliner); + get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel); + eOutlinerIdOpTypes event = RNA_enum_get(op->ptr, "type"); switch (event) { case OUTLINER_IDOP_UNLINK: { /* unlink datablock from its parent */ @@ -1818,7 +1879,6 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) break; } case OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE: { - /* make local */ outliner_do_libdata_operation(C, op->reports, scene, @@ -1830,7 +1890,6 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) break; } case OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY: { - /* make local */ outliner_do_libdata_operation(C, op->reports, scene, @@ -1842,7 +1901,6 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) break; } case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET: { - /* make local */ outliner_do_libdata_operation(C, op->reports, scene, @@ -1854,7 +1912,6 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) break; } case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET_HIERARCHY: { - /* make local */ outliner_do_libdata_operation(C, op->reports, scene, @@ -1865,6 +1922,28 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) ED_undo_push(C, "Reset Overridden Data Hierarchy"); break; } + case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY: { + outliner_do_libdata_operation(C, + op->reports, + scene, + space_outliner, + &space_outliner->tree, + id_override_library_resync_fn, + &(OutlinerLibOverrideData){.do_hierarchy = true}); + ED_undo_push(C, "Resync Overridden Data Hierarchy"); + break; + } + case OUTLINER_IDOP_OVERRIDE_LIBRARY_DELETE_HIERARCHY: { + outliner_do_libdata_operation(C, + op->reports, + scene, + space_outliner, + &space_outliner->tree, + id_override_library_delete_fn, + &(OutlinerLibOverrideData){.do_hierarchy = true}); + ED_undo_push(C, "Delete Overridden Data Hierarchy"); + break; + } case OUTLINER_IDOP_SINGLE: { /* make single user */ switch (idlevel) { @@ -2038,18 +2117,16 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; - eOutlinerLibOpTypes event; /* check for invalid states */ if (space_outliner == NULL) { return OPERATOR_CANCELLED; } - set_operation_types( - space_outliner, &space_outliner->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); - - event = RNA_enum_get(op->ptr, "type"); + TreeElement *te = get_target_element(space_outliner); + get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel); + eOutlinerLibOpTypes event = RNA_enum_get(op->ptr, "type"); switch (event) { case OL_LIB_RENAME: { outliner_do_libdata_operation( @@ -2171,8 +2248,9 @@ static int outliner_action_set_exec(bContext *C, wmOperator *op) if (space_outliner == NULL) { return OPERATOR_CANCELLED; } - set_operation_types( - space_outliner, &space_outliner->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); + + TreeElement *te = get_target_element(space_outliner); + get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel); /* get action to use */ act = BLI_findlink(&bmain->actions, RNA_enum_get(op->ptr, "action")); @@ -2279,22 +2357,21 @@ static int outliner_animdata_operation_exec(bContext *C, wmOperator *op) wmWindowManager *wm = CTX_wm_manager(C); SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; - eOutliner_AnimDataOps event; /* check for invalid states */ if (space_outliner == NULL) { return OPERATOR_CANCELLED; } - event = RNA_enum_get(op->ptr, "type"); - set_operation_types( - space_outliner, &space_outliner->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); + TreeElement *te = get_target_element(space_outliner); + get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel); if (datalevel != TSE_ANIM_DATA) { return OPERATOR_CANCELLED; } /* perform the core operation */ + eOutliner_AnimDataOps event = RNA_enum_get(op->ptr, "type"); switch (event) { case OUTLINER_ANIMOP_CLEAR_ADT: /* Remove Animation Data - this may remove the active action, in some cases... */ @@ -2384,15 +2461,10 @@ static const EnumPropertyItem prop_constraint_op_types[] = { static int outliner_constraint_operation_exec(bContext *C, wmOperator *op) { SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); - int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; - eOutliner_PropConstraintOps event; - - event = RNA_enum_get(op->ptr, "type"); - set_operation_types( - space_outliner, &space_outliner->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); + eOutliner_PropConstraintOps event = RNA_enum_get(op->ptr, "type"); outliner_do_data_operation( - space_outliner, datalevel, event, &space_outliner->tree, constraint_fn, C); + space_outliner, TSE_CONSTRAINT, event, &space_outliner->tree, constraint_fn, C); if (event == OL_CONSTRAINTOP_DELETE) { outliner_cleanup_tree(space_outliner); @@ -2436,15 +2508,10 @@ static const EnumPropertyItem prop_modifier_op_types[] = { static int outliner_modifier_operation_exec(bContext *C, wmOperator *op) { SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); - int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; - eOutliner_PropModifierOps event; - - event = RNA_enum_get(op->ptr, "type"); - set_operation_types( - space_outliner, &space_outliner->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); + eOutliner_PropModifierOps event = RNA_enum_get(op->ptr, "type"); outliner_do_data_operation( - space_outliner, datalevel, event, &space_outliner->tree, modifier_fn, C); + space_outliner, TSE_MODIFIER, event, &space_outliner->tree, modifier_fn, C); if (event == OL_MODIFIER_OP_DELETE) { outliner_cleanup_tree(space_outliner); @@ -2491,17 +2558,16 @@ static int outliner_data_operation_exec(bContext *C, wmOperator *op) { SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; - eOutliner_PropDataOps event; /* check for invalid states */ if (space_outliner == NULL) { return OPERATOR_CANCELLED; } - event = RNA_enum_get(op->ptr, "type"); - set_operation_types( - space_outliner, &space_outliner->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); + TreeElement *te = get_target_element(space_outliner); + get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel); + eOutliner_PropDataOps event = RNA_enum_get(op->ptr, "type"); switch (datalevel) { case TSE_POSE_CHANNEL: { outliner_do_data_operation( @@ -2600,134 +2666,117 @@ static int outliner_operator_menu(bContext *C, const char *opname) } static int do_outliner_operation_event(bContext *C, + ReportList *reports, ARegion *region, SpaceOutliner *space_outliner, - TreeElement *te, - const float mval[2]) + TreeElement *te) { - ReportList *reports = CTX_wm_reports(C); /* XXX... */ - - if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) { - int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; - TreeStoreElem *tselem = TREESTORE(te); - - /* select object that's clicked on and popup context menu */ - if (!(tselem->flag & TSE_SELECTED)) { + int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; + TreeStoreElem *tselem = TREESTORE(te); - if (outliner_flag_is_any_test(&space_outliner->tree, TSE_SELECTED, 1)) { - outliner_flag_set(&space_outliner->tree, TSE_SELECTED, 0); - } + int clear_flag = TSE_ACTIVE; + if (!(tselem->flag & TSE_SELECTED)) { + clear_flag |= TSE_SELECTED; + } - tselem->flag |= TSE_SELECTED; + outliner_flag_set(&space_outliner->tree, clear_flag, false); + tselem->flag |= TSE_SELECTED | TSE_ACTIVE; - /* Only redraw, don't rebuild here because TreeElement pointers will - * become invalid and operations will crash. */ - ED_region_tag_redraw_no_rebuild(region); - ED_outliner_select_sync_from_outliner(C, space_outliner); - } + /* Only redraw, don't rebuild here because TreeElement pointers will + * become invalid and operations will crash. */ + ED_region_tag_redraw_no_rebuild(region); + ED_outliner_select_sync_from_outliner(C, space_outliner); - set_operation_types( - space_outliner, &space_outliner->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); + get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel); - if (scenelevel) { - if (objectlevel || datalevel || idlevel) { - BKE_report(reports, RPT_WARNING, "Mixed selection"); - return OPERATOR_CANCELLED; - } - return outliner_operator_menu(C, "OUTLINER_OT_scene_operation"); + if (scenelevel) { + if (objectlevel || datalevel || idlevel) { + BKE_report(reports, RPT_WARNING, "Mixed selection"); + return OPERATOR_CANCELLED; } - if (objectlevel) { - WM_menu_name_call(C, "OUTLINER_MT_object", WM_OP_INVOKE_REGION_WIN); - return OPERATOR_FINISHED; + return outliner_operator_menu(C, "OUTLINER_OT_scene_operation"); + } + if (objectlevel) { + WM_menu_name_call(C, "OUTLINER_MT_object", WM_OP_INVOKE_REGION_WIN); + return OPERATOR_FINISHED; + } + if (idlevel) { + if (idlevel == -1 || datalevel) { + BKE_report(reports, RPT_WARNING, "Mixed selection"); + return OPERATOR_CANCELLED; } - if (idlevel) { - if (idlevel == -1 || datalevel) { - BKE_report(reports, RPT_WARNING, "Mixed selection"); - return OPERATOR_CANCELLED; - } - switch (idlevel) { - case ID_GR: - WM_menu_name_call(C, "OUTLINER_MT_collection", WM_OP_INVOKE_REGION_WIN); - return OPERATOR_FINISHED; - break; - case ID_LI: - return outliner_operator_menu(C, "OUTLINER_OT_lib_operation"); - break; - default: - return outliner_operator_menu(C, "OUTLINER_OT_id_operation"); - break; - } - } - else if (datalevel) { - if (datalevel == -1) { - BKE_report(reports, RPT_WARNING, "Mixed selection"); - return OPERATOR_CANCELLED; - } - if (datalevel == TSE_ANIM_DATA) { - return outliner_operator_menu(C, "OUTLINER_OT_animdata_operation"); - } - if (datalevel == TSE_DRIVER_BASE) { - /* do nothing... no special ops needed yet */ - return OPERATOR_CANCELLED; - } - if (datalevel == TSE_LAYER_COLLECTION) { + switch (idlevel) { + case ID_GR: WM_menu_name_call(C, "OUTLINER_MT_collection", WM_OP_INVOKE_REGION_WIN); return OPERATOR_FINISHED; - } - if (ELEM(datalevel, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) { - WM_menu_name_call(C, "OUTLINER_MT_collection_new", WM_OP_INVOKE_REGION_WIN); - return OPERATOR_FINISHED; - } - if (datalevel == TSE_ID_BASE) { - /* do nothing... there are no ops needed here yet */ - return 0; - } - if (datalevel == TSE_CONSTRAINT) { - return outliner_operator_menu(C, "OUTLINER_OT_constraint_operation"); - } - if (datalevel == TSE_MODIFIER) { - return outliner_operator_menu(C, "OUTLINER_OT_modifier_operation"); - } - return outliner_operator_menu(C, "OUTLINER_OT_data_operation"); + break; + case ID_LI: + return outliner_operator_menu(C, "OUTLINER_OT_lib_operation"); + break; + default: + return outliner_operator_menu(C, "OUTLINER_OT_id_operation"); + break; } - - return 0; } - - for (te = te->subtree.first; te; te = te->next) { - int retval = do_outliner_operation_event(C, region, space_outliner, te, mval); - if (retval) { - return retval; + else if (datalevel) { + if (datalevel == -1) { + BKE_report(reports, RPT_WARNING, "Mixed selection"); + return OPERATOR_CANCELLED; } + if (datalevel == TSE_ANIM_DATA) { + return outliner_operator_menu(C, "OUTLINER_OT_animdata_operation"); + } + if (datalevel == TSE_DRIVER_BASE) { + /* do nothing... no special ops needed yet */ + return OPERATOR_CANCELLED; + } + if (datalevel == TSE_LAYER_COLLECTION) { + WM_menu_name_call(C, "OUTLINER_MT_collection", WM_OP_INVOKE_REGION_WIN); + return OPERATOR_FINISHED; + } + if (ELEM(datalevel, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) { + WM_menu_name_call(C, "OUTLINER_MT_collection_new", WM_OP_INVOKE_REGION_WIN); + return OPERATOR_FINISHED; + } + if (datalevel == TSE_ID_BASE) { + /* do nothing... there are no ops needed here yet */ + return 0; + } + if (datalevel == TSE_CONSTRAINT) { + return outliner_operator_menu(C, "OUTLINER_OT_constraint_operation"); + } + if (datalevel == TSE_MODIFIER) { + return outliner_operator_menu(C, "OUTLINER_OT_modifier_operation"); + } + return outliner_operator_menu(C, "OUTLINER_OT_data_operation"); } return 0; } -static int outliner_operation(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) +static int outliner_operation(bContext *C, wmOperator *op, const wmEvent *event) { ARegion *region = CTX_wm_region(C); SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); uiBut *but = UI_context_active_but_get(C); - TreeElement *te; - float fmval[2]; + float view_mval[2]; if (but) { UI_but_tooltip_timer_remove(C, but); } - UI_view2d_region_to_view(®ion->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); + UI_view2d_region_to_view( + ®ion->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]); - for (te = space_outliner->tree.first; te; te = te->next) { - int retval = do_outliner_operation_event(C, region, space_outliner, te, fmval); - if (retval) { - return retval; - } + TreeElement *hovered_te = outliner_find_item_at_y( + space_outliner, &space_outliner->tree, view_mval[1]); + if (!hovered_te) { + /* Let this fall through to 'OUTLINER_MT_context_menu'. */ + return OPERATOR_PASS_THROUGH; } - /* Let this fall through to 'OUTLINER_MT_context_menu'. */ - return OPERATOR_PASS_THROUGH; + return do_outliner_operation_event(C, op->reports, region, space_outliner, hovered_te); } /* Menu only! Calls other operators */ diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 60058c82283..d21be1413e1 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -32,6 +32,7 @@ #include "DNA_camera_types.h" #include "DNA_collection_types.h" #include "DNA_constraint_types.h" +#include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" #include "DNA_hair_types.h" #include "DNA_key_types.h" @@ -46,6 +47,7 @@ #include "DNA_pointcloud_types.h" #include "DNA_scene_types.h" #include "DNA_sequence_types.h" +#include "DNA_shader_fx_types.h" #include "DNA_simulation_types.h" #include "DNA_speaker_types.h" #include "DNA_volume_types.h" @@ -552,6 +554,72 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner, } } + /* Grease Pencil modifiers. */ + if (!BLI_listbase_is_empty(&ob->greasepencil_modifiers)) { + GpencilModifierData *md; + TreeElement *ten_mod = outliner_add_element( + space_outliner, &te->subtree, ob, te, TSE_MODIFIER_BASE, 0); + int index; + + ten_mod->name = IFACE_("Modifiers"); + for (index = 0, md = ob->greasepencil_modifiers.first; md; index++, md = md->next) { + TreeElement *ten = outliner_add_element( + space_outliner, &ten_mod->subtree, ob, ten_mod, TSE_MODIFIER, index); + ten->name = md->name; + ten->directdata = md; + + if (md->type == eGpencilModifierType_Armature) { + outliner_add_element(space_outliner, + &ten->subtree, + ((ArmatureGpencilModifierData *)md)->object, + ten, + TSE_LINKED_OB, + 0); + } + else if (md->type == eGpencilModifierType_Hook) { + outliner_add_element(space_outliner, + &ten->subtree, + ((HookGpencilModifierData *)md)->object, + ten, + TSE_LINKED_OB, + 0); + } + else if (md->type == eGpencilModifierType_Lattice) { + outliner_add_element(space_outliner, + &ten->subtree, + ((LatticeGpencilModifierData *)md)->object, + ten, + TSE_LINKED_OB, + 0); + } + } + } + + /* Grease Pencil effects. */ + if (!BLI_listbase_is_empty(&ob->shader_fx)) { + ShaderFxData *fx; + TreeElement *ten_fx = outliner_add_element( + space_outliner, &te->subtree, ob, te, TSE_EFFECT_BASE, 0); + int index; + + ten_fx->name = IFACE_("Effects"); + for (index = 0, fx = ob->shader_fx.first; fx; index++, fx = fx->next) { + TreeElement *ten = outliner_add_element( + space_outliner, &ten_fx->subtree, ob, ten_fx, TSE_EFFECT, index); + ten->name = fx->name; + ten->directdata = fx; + + if (fx->type == eShaderFxType_Swirl) { + outliner_add_element(space_outliner, + &ten->subtree, + ((SwirlShaderFxData *)fx)->object, + ten, + TSE_LINKED_OB, + 0); + } + } + } + /* vertex groups */ if (ob->defbase.first) { bDeformGroup *defgroup; @@ -1787,49 +1855,25 @@ static int treesort_alpha(const void *v1, const void *v2) return 0; } -/* this is nice option for later? doesn't look too useful... */ -#if 0 -static int treesort_obtype_alpha(const void *v1, const void *v2) +static int treesort_type(const void *v1, const void *v2) { - const tTreeSort *x1 = v1, *x2 = v2; + const tTreeSort *x1 = v1; + const tTreeSort *x2 = v2; - /* first put objects last (hierarchy) */ - if (x1->idcode == ID_OB && x2->idcode != ID_OB) { + if (((Object *)x1->id)->type > ((Object *)x2->id)->type) { return 1; } - else if (x2->idcode == ID_OB && x1->idcode != ID_OB) { + else if (((Object *)x2->id)->type > ((Object *)x1->id)->type) { return -1; } else { - /* 2nd we check ob type */ - if (x1->idcode == ID_OB && x2->idcode == ID_OB) { - if (((Object *)x1->id)->type > ((Object *)x2->id)->type) { - return 1; - } - else if (((Object *)x1->id)->type > ((Object *)x2->id)->type) { - return -1; - } - else { - return 0; - } - } - else { - int comp = BLI_strcasecmp_natural(x1->name, x2->name); - - if (comp > 0) { - return 1; - } - else if (comp < 0) { - return -1; - } - return 0; - } + /* Compare by name */ + return treesort_alpha(v1, v2); } } -#endif -/* sort happens on each subtree individual */ -static void outliner_sort(ListBase *lb) +/* TODO (Nathan): Should children still be sorted? */ +static void outliner_collections_children_sort(ListBase *lb) { TreeElement *te; TreeStoreElem *tselem; @@ -1840,48 +1884,23 @@ static void outliner_sort(ListBase *lb) } tselem = TREESTORE(te); - /* sorting rules; only object lists, ID lists, or deformgroups */ - if (ELEM(tselem->type, TSE_DEFGROUP, TSE_ID_BASE) || - (tselem->type == 0 && te->idcode == ID_OB)) { + /* Sorting rules: only object lists. */ + if (tselem->type == 0 && te->idcode == ID_OB) { int totelem = BLI_listbase_count(lb); if (totelem > 1) { tTreeSort *tear = MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array"); tTreeSort *tp = tear; - int skip = 0; for (te = lb->first; te; te = te->next, tp++) { tselem = TREESTORE(te); tp->te = te; tp->name = te->name; tp->idcode = te->idcode; - - if (tselem->type && tselem->type != TSE_DEFGROUP) { - tp->idcode = 0; /* Don't sort this. */ - } - if (tselem->type == TSE_ID_BASE) { - tp->idcode = 1; /* Do sort this. */ - } - tp->id = tselem->id; } - /* just sort alphabetically */ - if (tear->idcode == 1) { - qsort(tear, totelem, sizeof(tTreeSort), treesort_alpha); - } - else { - /* keep beginning of list */ - for (tp = tear, skip = 0; skip < totelem; skip++, tp++) { - if (tp->idcode) { - break; - } - } - - if (skip < totelem) { - qsort(tear + skip, totelem - skip, sizeof(tTreeSort), treesort_alpha_ob); - } - } + qsort(tear, totelem, sizeof(tTreeSort), treesort_child_not_in_collection); BLI_listbase_clear(lb); tp = tear; @@ -1894,54 +1913,130 @@ static void outliner_sort(ListBase *lb) } for (te = lb->first; te; te = te->next) { - outliner_sort(&te->subtree); + outliner_collections_children_sort(&te->subtree); } } -static void outliner_collections_children_sort(ListBase *lb) +static bool outliner_is_sort_item(TreeElement *te) { - TreeElement *te; - TreeStoreElem *tselem; + TreeStoreElem *tselem = TREESTORE(te); + return (tselem->type == 0 && te->idcode == ID_OB) || outliner_is_collection_tree_element(te) || + (ELEM(tselem->type, TSE_BONE, TSE_EBONE, TSE_POSE_CHANNEL)); +} - te = lb->last; - if (te == NULL) { +/* Sort collections and objects separately on each outliner subtree. */ +static void outliner_tree_sort(SpaceOutliner *space_outliner, ListBase *tree) +{ + if (BLI_listbase_is_empty(tree)) { return; } - tselem = TREESTORE(te); - /* Sorting rules: only object lists. */ - if (tselem->type == 0 && te->idcode == ID_OB) { - int totelem = BLI_listbase_count(lb); + TreeElement *te_last = tree->last; + TreeStoreElem *tselem; - if (totelem > 1) { - tTreeSort *tear = MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array"); - tTreeSort *tp = tear; + /* Only sort collections and objects */ + if (outliner_is_sort_item(te_last)) { + int num_elems = BLI_listbase_count(tree); - for (te = lb->first; te; te = te->next, tp++) { + if (num_elems > 1) { + tTreeSort *tree_sort = MEM_mallocN(num_elems * sizeof(tTreeSort), "tree sort array"); + tTreeSort *tree_sort_p = tree_sort; + int num_collections = 0; + + for (TreeElement *te = tree->first; te; te = te->next, tree_sort_p++) { tselem = TREESTORE(te); - tp->te = te; - tp->name = te->name; - tp->idcode = te->idcode; - tp->id = tselem->id; + tree_sort_p->te = te; + tree_sort_p->name = te->name; + tree_sort_p->idcode = te->idcode; + + if (tselem->type && tselem->type != TSE_DEFGROUP) { + tree_sort_p->idcode = 0; /* Don't sort this. */ + } + if (tselem->type == TSE_ID_BASE) { + tree_sort_p->idcode = 1; /* Do sort this. */ + } + + if (outliner_is_collection_tree_element(te)) { + num_collections++; + } + + tree_sort_p->id = tselem->id; } - qsort(tear, totelem, sizeof(tTreeSort), treesort_child_not_in_collection); + /* Skip beginning of list */ + int skip = 0; + if (!outliner_is_sort_item(tree_sort->te)) { + for (tree_sort_p = tree_sort, skip = 0; skip < num_elems; skip++, tree_sort_p++) { + if (outliner_is_sort_item(tree_sort_p->te)) { + break; + } + } + } - BLI_listbase_clear(lb); - tp = tear; - while (totelem--) { - BLI_addtail(lb, tp->te); - tp++; + /* Sort collections. */ + if (num_collections > 0) { + switch (space_outliner->sort_method) { + case SO_SORT_ALPHA: + qsort(tree_sort + skip, num_collections - skip, sizeof(tTreeSort), treesort_alpha); + break; + case SO_SORT_TYPE: + qsort(tree_sort + skip, num_collections - skip, sizeof(tTreeSort), treesort_alpha); + break; + } } - MEM_freeN(tear); + + /* Sort objects. */ + if (num_elems - num_collections - skip > 0) { + switch (space_outliner->sort_method) { + case SO_SORT_ALPHA: + qsort(tree_sort + skip + num_collections, + num_elems - num_collections - skip, + sizeof(tTreeSort), + treesort_alpha); + break; + case SO_SORT_TYPE: + qsort(tree_sort + skip + num_collections, + num_elems - num_collections - skip, + sizeof(tTreeSort), + treesort_type); + break; + } + } + + /* Copy sorted list back into tree */ + BLI_listbase_clear(tree); + tree_sort_p = tree_sort; + while (num_elems--) { + BLI_addtail(tree, tree_sort_p->te); + tree_sort_p++; + } + MEM_freeN(tree_sort); } } - for (te = lb->first; te; te = te->next) { - outliner_collections_children_sort(&te->subtree); + LISTBASE_FOREACH (TreeElement *, te, tree) { + outliner_tree_sort(space_outliner, &te->subtree); } } +#if 0 +void f(SpaceOutliner *space_outliner) +{ + if (space_outliner->sort_method == SO_SORT_ALPHA) { + outliner_sort(tree); + } + else if (space_outliner->sort_method == SO_SORT_TYPE) { + } + else if ((space_outliner->filter & SO_FILTER_NO_CHILDREN) == 0) { + /* We group the children that are in the collection before the ones that are not. + * This way we can try to draw them in a different style altogether. + * We also have to respect the original order of the elements in case alphabetical + * sorting is not enabled. This keep object data and modifiers before its children. */ + outliner_collections_children_sort(tree); + } +} +#endif + /* Filtering ----------------------------------------------- */ typedef struct OutlinerTreeElementFocus { @@ -2564,15 +2659,8 @@ void outliner_build_tree(Main *mainvar, } } - if ((space_outliner->flag & SO_SKIP_SORT_ALPHA) == 0) { - outliner_sort(&space_outliner->tree); - } - else if ((space_outliner->filter & SO_FILTER_NO_CHILDREN) == 0) { - /* We group the children that are in the collection before the ones that are not. - * This way we can try to draw them in a different style altogether. - * We also have to respect the original order of the elements in case alphabetical - * sorting is not enabled. This keep object data and modifiers before its children. */ - outliner_collections_children_sort(&space_outliner->tree); + if (space_outliner->sort_method != SO_SORT_FREE) { + outliner_tree_sort(space_outliner, &space_outliner->tree); } outliner_filter_tree(space_outliner, view_layer); diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index b14afed81dd..13483d0d580 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -305,7 +305,7 @@ static SpaceLink *outliner_create(const ScrArea *UNUSED(area), const Scene *UNUS space_outliner->show_restrict_flags = SO_RESTRICT_ENABLE | SO_RESTRICT_HIDE; space_outliner->outlinevis = SO_VIEW_LAYER; space_outliner->sync_select_dirty |= WM_OUTLINER_SYNC_SELECT_FROM_ALL; - space_outliner->flag |= SO_SYNC_SELECT; + space_outliner->flag = SO_SYNC_SELECT | SO_MODE_COLUMN; /* header */ region = MEM_callocN(sizeof(ARegion), "header for outliner"); diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 8a6b97b3834..eb066f6afea 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -1772,7 +1772,7 @@ void sequencer_draw_preview(const bContext *C, GPUFrameBuffer *framebuffer_overlay = GPU_viewport_framebuffer_overlay_get(viewport); GPU_framebuffer_bind_no_srgb(framebuffer_overlay); - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); if (sseq->render_size == SEQ_PROXY_RENDER_SIZE_NONE) { sequencer_preview_clear(); diff --git a/source/blender/editors/space_userpref/space_userpref.c b/source/blender/editors/space_userpref/space_userpref.c index 0242bb4fe24..3efdee9cec9 100644 --- a/source/blender/editors/space_userpref/space_userpref.c +++ b/source/blender/editors/space_userpref/space_userpref.c @@ -141,8 +141,7 @@ static void userpref_main_region_layout(const bContext *C, ARegion *region) BLI_str_tolower_ascii(id_lower, strlen(id_lower)); } - ED_region_panels_layout_ex( - C, region, ®ion->type->paneltypes, contexts, U.space_data.section_active, true, NULL); + ED_region_panels_layout_ex(C, region, ®ion->type->paneltypes, contexts, NULL); } static void userpref_operatortypes(void) diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index e5ba27cef07..de0b420a3b5 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -1323,9 +1323,7 @@ void ED_view3d_buttons_region_layout_ex(const bContext *C, paneltypes = &art->paneltypes; } - const bool vertical = true; - ED_region_panels_layout_ex( - C, region, paneltypes, contexts_base, -1, vertical, category_override); + ED_region_panels_layout_ex(C, region, paneltypes, contexts_base, category_override); } static void view3d_buttons_region_layout(const bContext *C, ARegion *region) @@ -1453,7 +1451,7 @@ static void view3d_tools_region_init(wmWindowManager *wm, ARegion *region) static void view3d_tools_region_draw(const bContext *C, ARegion *region) { - ED_region_panels_ex(C, region, (const char *[]){CTX_data_mode_string(C), NULL}, -1, true); + ED_region_panels_ex(C, region, (const char *[]){CTX_data_mode_string(C), NULL}); } /* area (not region) level listener */ diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 33b365b45aa..4cc48dfd175 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -1618,7 +1618,7 @@ void view3d_main_region_draw(const bContext *C, ARegion *region) GPU_pass_cache_garbage_collect(); /* No depth test for drawing action zones afterwards. */ - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); v3d->flag |= V3D_INVALID_BACKBUF; } @@ -2321,12 +2321,12 @@ void ED_view3d_draw_depth_gpencil(Depsgraph *depsgraph, Scene *scene, ARegion *r GPU_clear(GPU_DEPTH_BIT); - GPU_depth_test(true); + GPU_depth_test(GPU_DEPTH_LESS_EQUAL); GPUViewport *viewport = WM_draw_region_get_viewport(region); DRW_draw_depth_loop_gpencil(depsgraph, region, v3d, viewport); - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); } /* *********************** customdata **************** */ diff --git a/source/blender/editors/space_view3d/view3d_placement.c b/source/blender/editors/space_view3d/view3d_placement.c index 6c61c83731d..6c2f4df7004 100644 --- a/source/blender/editors/space_view3d/view3d_placement.c +++ b/source/blender/editors/space_view3d/view3d_placement.c @@ -586,23 +586,23 @@ static void draw_primitive_view(const struct bContext *C, ARegion *UNUSED(region UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, color); const bool use_depth = !XRAY_ENABLED(ipd->v3d); - const bool depth_test_enabled = GPU_depth_test_enabled(); + const eGPUDepthTest depth_test_enabled = GPU_depth_test_get(); if (use_depth) { - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); color[3] = 0.15f; draw_primitive_view_impl(C, ipd, color); } if (use_depth) { - GPU_depth_test(true); + GPU_depth_test(GPU_DEPTH_LESS_EQUAL); } color[3] = 1.0f; draw_primitive_view_impl(C, ipd, color); if (use_depth) { if (depth_test_enabled == false) { - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); } } } diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index b986ebb75b6..d015b5dcc89 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -1100,7 +1100,7 @@ int view3d_opengl_select(ViewContext *vc, wm, vc->win, depsgraph, scene, region, v3d, vc->rv3d->viewmat, NULL, &rect); if (!XRAY_ACTIVE(v3d)) { - GPU_depth_test(true); + GPU_depth_test(GPU_DEPTH_LESS_EQUAL); } /* If in xray mode, we select the wires in priority. */ @@ -1165,7 +1165,7 @@ int view3d_opengl_select(ViewContext *vc, wm, vc->win, depsgraph, scene, region, v3d, vc->rv3d->viewmat, NULL, NULL); if (!XRAY_ACTIVE(v3d)) { - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); } DRW_opengl_context_disable(); diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index 0aa6b4f6131..4e5eaf4bf51 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -785,7 +785,6 @@ void drawConstraint(TransInfo *t) else { if (tc->mode & CON_SELECT) { float vec[3]; - int depth_test_enabled; convertViewVec(t, vec, (t->mval[0] - t->con.imval[0]), (t->mval[1] - t->con.imval[1])); add_v3_v3(vec, t->center_global); @@ -794,9 +793,9 @@ void drawConstraint(TransInfo *t) drawLine(t, t->center_global, t->spacemtx[1], 'Y', 0); drawLine(t, t->center_global, t->spacemtx[2], 'Z', 0); - depth_test_enabled = GPU_depth_test_enabled(); + eGPUDepthTest depth_test_enabled = GPU_depth_test_get(); if (depth_test_enabled) { - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); } const uint shdr_pos = GPU_vertformat_attr_add( @@ -821,7 +820,7 @@ void drawConstraint(TransInfo *t) immUnbindProgram(); if (depth_test_enabled) { - GPU_depth_test(true); + GPU_depth_test(GPU_DEPTH_LESS_EQUAL); } } @@ -843,7 +842,6 @@ void drawPropCircle(const struct bContext *C, TransInfo *t) if (t->flag & T_PROP_EDIT) { RegionView3D *rv3d = CTX_wm_region_view3d(C); float tmat[4][4], imat[4][4]; - int depth_test_enabled; if (t->spacetype == SPACE_VIEW3D && rv3d != NULL) { copy_m4_m4(tmat, rv3d->viewmat); @@ -873,9 +871,9 @@ void drawPropCircle(const struct bContext *C, TransInfo *t) GPU_matrix_scale_2f(1.0f, (ysize / xsize) * (xmask / ymask)); } - depth_test_enabled = GPU_depth_test_enabled(); + eGPUDepthTest depth_test_enabled = GPU_depth_test_get(); if (depth_test_enabled) { - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); } uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); @@ -899,7 +897,7 @@ void drawPropCircle(const struct bContext *C, TransInfo *t) immUnbindProgram(); if (depth_test_enabled) { - GPU_depth_test(true); + GPU_depth_test(GPU_DEPTH_LESS_EQUAL); } GPU_matrix_pop(); diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c index dffee72205b..14ef5e87534 100644 --- a/source/blender/editors/transform/transform_gizmo_3d.c +++ b/source/blender/editors/transform/transform_gizmo_3d.c @@ -1343,7 +1343,7 @@ void drawDial3d(const TransInfo *t) BLI_assert(axis_idx >= MAN_AXIS_RANGE_ROT_START && axis_idx < MAN_AXIS_RANGE_ROT_END); gizmo_get_axis_color(axis_idx, NULL, color, color); - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); GPU_blend(GPU_BLEND_ALPHA); GPU_line_smooth(true); @@ -1359,7 +1359,7 @@ void drawDial3d(const TransInfo *t) }); GPU_line_smooth(false); - GPU_depth_test(true); + GPU_depth_test(GPU_DEPTH_LESS_EQUAL); GPU_blend(GPU_BLEND_NONE); } } diff --git a/source/blender/editors/transform/transform_mode_edge_slide.c b/source/blender/editors/transform/transform_mode_edge_slide.c index 45debe964f4..fe97a9fba87 100644 --- a/source/blender/editors/transform/transform_mode_edge_slide.c +++ b/source/blender/editors/transform/transform_mode_edge_slide.c @@ -1147,7 +1147,7 @@ void drawEdgeSlide(TransInfo *t) const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f; - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); GPU_blend(GPU_BLEND_ALPHA); @@ -1266,7 +1266,7 @@ void drawEdgeSlide(TransInfo *t) GPU_blend(GPU_BLEND_NONE); - GPU_depth_test(true); + GPU_depth_test(GPU_DEPTH_LESS_EQUAL); } static void edge_slide_snap_apply(TransInfo *t, float *value) diff --git a/source/blender/editors/transform/transform_mode_vert_slide.c b/source/blender/editors/transform/transform_mode_vert_slide.c index 11d0b375e6f..4367dd5ee92 100644 --- a/source/blender/editors/transform/transform_mode_vert_slide.c +++ b/source/blender/editors/transform/transform_mode_vert_slide.c @@ -390,7 +390,7 @@ void drawVertSlide(TransInfo *t) const int alpha_shade = -160; int i; - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); GPU_blend(GPU_BLEND_ALPHA); @@ -485,7 +485,7 @@ void drawVertSlide(TransInfo *t) GPU_matrix_pop(); - GPU_depth_test(true); + GPU_depth_test(GPU_DEPTH_LESS_EQUAL); } } } diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 09b5df82c2b..5db41570e00 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -184,7 +184,7 @@ void drawSnapping(const struct bContext *C, TransInfo *t) const float *loc_prev = NULL; const float *normal = NULL; - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); RegionView3D *rv3d = CTX_wm_region_view3d(C); if (!BLI_listbase_is_empty(&t->tsnap.points)) { @@ -228,7 +228,7 @@ void drawSnapping(const struct bContext *C, TransInfo *t) ED_gizmotypes_snap_3d_draw_util( rv3d, loc_prev, loc_cur, normal, col, activeCol, t->tsnap.snapElem); - GPU_depth_test(true); + GPU_depth_test(GPU_DEPTH_LESS_EQUAL); } } else if (t->spacetype == SPACE_IMAGE) { diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index faeefcb989e..d80e7f3c754 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -451,13 +451,13 @@ static void draw_uvs(SpaceImage *sima, GPU_batch_program_set_builtin(batch->edges, shader); /* Inner Line. Use depth test to insure selection is drawn on top. */ - GPU_depth_test(true); + GPU_depth_test(GPU_DEPTH_LESS_EQUAL); GPU_line_width(1.0f); GPU_batch_uniform_4fv(batch->edges, "edgeColor", col1); GPU_batch_uniform_4fv(batch->edges, "selectColor", col2); GPU_batch_uniform_1f(batch->edges, "dashWidth", dash_width); GPU_batch_draw(batch->edges); - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); GPU_provoking_vertex(GPU_VERTEX_LAST); } diff --git a/source/blender/functions/tests/FN_array_spans_test.cc b/source/blender/functions/tests/FN_array_spans_test.cc index 9a632b58be8..af2bc0aad91 100644 --- a/source/blender/functions/tests/FN_array_spans_test.cc +++ b/source/blender/functions/tests/FN_array_spans_test.cc @@ -50,7 +50,9 @@ TEST(virtual_array_span, MultipleArrayConstructor) std::array<int, 2> values1 = {6, 7}; std::array<int, 1> values2 = {8}; std::array<const int *, 3> starts = {values0.data(), values1.data(), values2.data()}; - std::array<int64_t, 3> sizes{values0.size(), values1.size(), values2.size()}; + std::array<int64_t, 3> sizes{static_cast<int64_t>(values0.size()), + static_cast<int64_t>(values1.size()), + static_cast<int64_t>(values2.size())}; VArraySpan<int> span{starts, sizes}; EXPECT_EQ(span.size(), 3); diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 45b379c5e0a..50a5a0243f8 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -93,6 +93,7 @@ set(SRC opengl/gl_context.cc opengl/gl_drawlist.cc opengl/gl_shader.cc + opengl/gl_shader_interface.cc opengl/gl_state.cc opengl/gl_vertex_array.cc @@ -119,7 +120,6 @@ set(SRC GPU_primitive.h GPU_select.h GPU_shader.h - GPU_shader_interface.h GPU_state.h GPU_texture.h GPU_uniformbuffer.h @@ -140,6 +140,7 @@ set(SRC intern/gpu_private.h intern/gpu_select_private.h intern/gpu_shader_private.hh + intern/gpu_shader_interface.hh intern/gpu_state_private.hh intern/gpu_vertex_format_private.h @@ -148,6 +149,7 @@ set(SRC opengl/gl_context.hh opengl/gl_drawlist.hh opengl/gl_shader.hh + opengl/gl_shader_interface.hh opengl/gl_state.hh opengl/gl_vertex_array.hh ) diff --git a/source/blender/gpu/GPU_context.h b/source/blender/gpu/GPU_context.h index e3d47cfe084..be7e604fb96 100644 --- a/source/blender/gpu/GPU_context.h +++ b/source/blender/gpu/GPU_context.h @@ -27,7 +27,6 @@ #include "GPU_batch.h" #include "GPU_common.h" -#include "GPU_shader_interface.h" #ifdef __cplusplus extern "C" { diff --git a/source/blender/gpu/GPU_immediate.h b/source/blender/gpu/GPU_immediate.h index 41d4f5d28d3..6057770d2d9 100644 --- a/source/blender/gpu/GPU_immediate.h +++ b/source/blender/gpu/GPU_immediate.h @@ -29,7 +29,6 @@ #include "GPU_immediate_util.h" #include "GPU_primitive.h" #include "GPU_shader.h" -#include "GPU_shader_interface.h" #include "GPU_texture.h" #include "GPU_vertex_format.h" @@ -103,13 +102,11 @@ void immVertex2iv(uint attr_id, const int data[2]); /* Provide uniform values that don't change for the entire draw call. */ void immUniform1i(const char *name, int x); -void immUniform4iv(const char *name, const int data[4]); void immUniform1f(const char *name, float x); void immUniform2f(const char *name, float x, float y); void immUniform2fv(const char *name, const float data[2]); void immUniform3f(const char *name, float x, float y, float z); void immUniform3fv(const char *name, const float data[3]); -void immUniformArray3fv(const char *name, const float *data, int count); void immUniform4f(const char *name, float x, float y, float z, float w); void immUniform4fv(const char *name, const float data[4]); void immUniformArray4fv(const char *bare_name, const float *data, int count); diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index 99fcae19984..b38cc1f3244 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -27,7 +27,6 @@ extern "C" { #endif -struct GPUShaderInterface; struct GPUTexture; struct GPUUniformBuffer; struct GPUVertBuf; @@ -35,8 +34,6 @@ struct GPUVertBuf; /* TODO(fclem) These members should be private and the * whole struct should just be an opaque pointer. */ typedef struct GPUShader { - /** Uniform & attribute locations for shader. */ - struct GPUShaderInterface *interface; /** For debugging purpose. */ char name[64]; } GPUShader; @@ -90,6 +87,41 @@ void GPU_shader_transform_feedback_disable(GPUShader *shader); int GPU_shader_get_program(GPUShader *shader); +typedef enum { + GPU_UNIFORM_MODEL = 0, /* mat4 ModelMatrix */ + GPU_UNIFORM_VIEW, /* mat4 ViewMatrix */ + GPU_UNIFORM_MODELVIEW, /* mat4 ModelViewMatrix */ + GPU_UNIFORM_PROJECTION, /* mat4 ProjectionMatrix */ + GPU_UNIFORM_VIEWPROJECTION, /* mat4 ViewProjectionMatrix */ + GPU_UNIFORM_MVP, /* mat4 ModelViewProjectionMatrix */ + + GPU_UNIFORM_MODEL_INV, /* mat4 ModelMatrixInverse */ + GPU_UNIFORM_VIEW_INV, /* mat4 ViewMatrixInverse */ + GPU_UNIFORM_MODELVIEW_INV, /* mat4 ModelViewMatrixInverse */ + GPU_UNIFORM_PROJECTION_INV, /* mat4 ProjectionMatrixInverse */ + GPU_UNIFORM_VIEWPROJECTION_INV, /* mat4 ViewProjectionMatrixInverse */ + + GPU_UNIFORM_NORMAL, /* mat3 NormalMatrix */ + GPU_UNIFORM_ORCO, /* vec4 OrcoTexCoFactors[] */ + GPU_UNIFORM_CLIPPLANES, /* vec4 WorldClipPlanes[] */ + + GPU_UNIFORM_COLOR, /* vec4 color */ + GPU_UNIFORM_BASE_INSTANCE, /* int baseInstance */ + GPU_UNIFORM_RESOURCE_CHUNK, /* int resourceChunk */ + GPU_UNIFORM_RESOURCE_ID, /* int resourceId */ + GPU_UNIFORM_SRGB_TRANSFORM, /* bool srgbTarget */ + + GPU_NUM_UNIFORMS, /* Special value, denotes number of builtin uniforms. */ +} GPUUniformBuiltin; + +typedef enum { + GPU_UNIFORM_BLOCK_VIEW = 0, /* viewBlock */ + GPU_UNIFORM_BLOCK_MODEL, /* modelBlock */ + GPU_UNIFORM_BLOCK_INFO, /* infoBlock */ + + GPU_NUM_UNIFORM_BLOCKS, /* Special value, denotes number of builtin uniforms block. */ +} GPUUniformBlockBuiltin; + void GPU_shader_set_srgb_uniform(GPUShader *shader); int GPU_shader_get_uniform(GPUShader *shader, const char *name); @@ -123,8 +155,6 @@ void GPU_shader_uniform_4fv_array(GPUShader *sh, const char *name, int len, cons int GPU_shader_get_attribute(GPUShader *shader, const char *name); -char *GPU_shader_get_binary(GPUShader *shader, uint *r_binary_format, int *r_binary_len); - void GPU_shader_set_framebuffer_srgb_target(int use_srgb_to_linear); /* Builtin/Non-generated shaders */ diff --git a/source/blender/gpu/GPU_shader_interface.h b/source/blender/gpu/GPU_shader_interface.h deleted file mode 100644 index 47e4e432d66..00000000000 --- a/source/blender/gpu/GPU_shader_interface.h +++ /dev/null @@ -1,117 +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) 2016 by Mike Erwin. - * All rights reserved. - */ - -/** \file - * \ingroup gpu - * - * GPU shader interface (C --> GLSL) - */ - -#pragma once - -#include "GPU_common.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - GPU_UNIFORM_MODEL = 0, /* mat4 ModelMatrix */ - GPU_UNIFORM_VIEW, /* mat4 ViewMatrix */ - GPU_UNIFORM_MODELVIEW, /* mat4 ModelViewMatrix */ - GPU_UNIFORM_PROJECTION, /* mat4 ProjectionMatrix */ - GPU_UNIFORM_VIEWPROJECTION, /* mat4 ViewProjectionMatrix */ - GPU_UNIFORM_MVP, /* mat4 ModelViewProjectionMatrix */ - - GPU_UNIFORM_MODEL_INV, /* mat4 ModelMatrixInverse */ - GPU_UNIFORM_VIEW_INV, /* mat4 ViewMatrixInverse */ - GPU_UNIFORM_MODELVIEW_INV, /* mat4 ModelViewMatrixInverse */ - GPU_UNIFORM_PROJECTION_INV, /* mat4 ProjectionMatrixInverse */ - GPU_UNIFORM_VIEWPROJECTION_INV, /* mat4 ViewProjectionMatrixInverse */ - - GPU_UNIFORM_NORMAL, /* mat3 NormalMatrix */ - GPU_UNIFORM_ORCO, /* vec4 OrcoTexCoFactors[] */ - GPU_UNIFORM_CLIPPLANES, /* vec4 WorldClipPlanes[] */ - - GPU_UNIFORM_COLOR, /* vec4 color */ - GPU_UNIFORM_BASE_INSTANCE, /* int baseInstance */ - GPU_UNIFORM_RESOURCE_CHUNK, /* int resourceChunk */ - GPU_UNIFORM_RESOURCE_ID, /* int resourceId */ - GPU_UNIFORM_SRGB_TRANSFORM, /* bool srgbTarget */ - - GPU_NUM_UNIFORMS, /* Special value, denotes number of builtin uniforms. */ -} GPUUniformBuiltin; - -typedef enum { - GPU_UNIFORM_BLOCK_VIEW = 0, /* viewBlock */ - GPU_UNIFORM_BLOCK_MODEL, /* modelBlock */ - GPU_UNIFORM_BLOCK_INFO, /* infoBlock */ - - GPU_NUM_UNIFORM_BLOCKS, /* Special value, denotes number of builtin uniforms block. */ -} GPUUniformBlockBuiltin; - -typedef struct GPUShaderInput { - uint32_t name_offset; - uint32_t name_hash; - int32_t location; - /** Defined at interface creation or in shader. Only for Samplers, UBOs and Vertex Attribs. */ - int32_t binding; -} GPUShaderInput; - -#define GPU_SHADERINTERFACE_REF_ALLOC_COUNT 16 - -typedef struct GPUShaderInterface { - /** Buffer containing all inputs names separated by '\0'. */ - char *name_buffer; - /** Reference to GPUBatches using this interface */ - void **batches; - uint batches_len; - /** Input counts. */ - uint attribute_len; - uint ubo_len; - uint uniform_len; - /** Enabled bindpoints that needs to be fed with data. */ - uint16_t enabled_attr_mask; - uint16_t enabled_ubo_mask; - uint64_t enabled_tex_mask; - /** Opengl Location of builtin uniforms. Fast access, no lookup needed. */ - int32_t builtins[GPU_NUM_UNIFORMS]; - int32_t builtin_blocks[GPU_NUM_UNIFORM_BLOCKS]; - /** Flat array. In this order: Attributes, Ubos, Uniforms. */ - GPUShaderInput inputs[0]; -} GPUShaderInterface; - -GPUShaderInterface *GPU_shaderinterface_create(int32_t program_id); -void GPU_shaderinterface_discard(GPUShaderInterface *); - -const GPUShaderInput *GPU_shaderinterface_uniform(const GPUShaderInterface *, const char *name); -int32_t GPU_shaderinterface_uniform_builtin(const GPUShaderInterface *shaderface, - GPUUniformBuiltin builtin); -int32_t GPU_shaderinterface_block_builtin(const GPUShaderInterface *shaderface, - GPUUniformBlockBuiltin builtin); -const GPUShaderInput *GPU_shaderinterface_ubo(const GPUShaderInterface *, const char *name); -const GPUShaderInput *GPU_shaderinterface_attr(const GPUShaderInterface *, const char *name); - -/* keep track of batches using this interface */ -void GPU_shaderinterface_add_batch_ref(GPUShaderInterface *interface, void *cache); -void GPU_shaderinterface_remove_batch_ref(GPUShaderInterface *interface, void *cache); - -#ifdef __cplusplus -} -#endif diff --git a/source/blender/gpu/GPU_state.h b/source/blender/gpu/GPU_state.h index 8bc5c2b8397..6a59baa38f0 100644 --- a/source/blender/gpu/GPU_state.h +++ b/source/blender/gpu/GPU_state.h @@ -54,7 +54,7 @@ typedef enum eGPUBlend { /** Replace logic op: SRC * (1 - DST) * NOTE: Does not modify alpha. */ GPU_BLEND_INVERT, - /** Order independant transparency. + /** Order independent transparency. * NOTE: Cannot be used as is. Needs special setup (framebuffer, shader ...). */ GPU_BLEND_OIT, /** Special blend to add color under and multiply dst color by src alpha. */ @@ -66,9 +66,9 @@ typedef enum eGPUBlend { typedef enum eGPUDepthTest { GPU_DEPTH_NONE = 0, - GPU_DEPTH_ALWAYS, + GPU_DEPTH_ALWAYS, /* Used to draw to the depth buffer without really testing. */ GPU_DEPTH_LESS, - GPU_DEPTH_LESS_EQUAL, + GPU_DEPTH_LESS_EQUAL, /* Default. */ GPU_DEPTH_EQUAL, GPU_DEPTH_GREATER, GPU_DEPTH_GREATER_EQUAL, @@ -106,11 +106,10 @@ extern "C" { void GPU_blend(eGPUBlend blend); void GPU_face_culling(eGPUFaceCullTest culling); -void GPU_front_facing(bool invert); +void GPU_depth_test(eGPUDepthTest test); void GPU_provoking_vertex(eGPUProvokingVertex vert); +void GPU_front_facing(bool invert); void GPU_depth_range(float near, float far); -void GPU_depth_test(bool enable); -bool GPU_depth_test_enabled(void); void GPU_scissor_test(bool enable); void GPU_line_smooth(bool enable); void GPU_line_width(float width); @@ -144,6 +143,7 @@ void GPU_stencil_write_mask_set(uint write_mask); void GPU_stencil_compare_mask_set(uint compare_mask); eGPUBlend GPU_blend_get(void); +eGPUDepthTest GPU_depth_test_get(void); eGPUWriteMask GPU_write_mask_get(void); void GPU_flush(void); diff --git a/source/blender/gpu/intern/gpu_attr_binding.cc b/source/blender/gpu/intern/gpu_attr_binding.cc index 6cb60884620..2a48107e190 100644 --- a/source/blender/gpu/intern/gpu_attr_binding.cc +++ b/source/blender/gpu/intern/gpu_attr_binding.cc @@ -61,9 +61,7 @@ static void write_attr_location(GPUAttrBinding *binding, uint a_idx, uint locati binding->enabled_bits |= 1 << a_idx; } -void get_attr_locations(const GPUVertFormat *format, - GPUAttrBinding *binding, - const GPUShaderInterface *shaderface) +void get_attr_locations(const GPUVertFormat *format, GPUAttrBinding *binding, GPUShader *shader) { AttrBinding_clear(binding); @@ -71,13 +69,12 @@ void get_attr_locations(const GPUVertFormat *format, const GPUVertAttr *a = &format->attrs[a_idx]; for (uint n_idx = 0; n_idx < a->name_len; n_idx++) { const char *name = GPU_vertformat_attr_name_get(format, a, n_idx); - const GPUShaderInput *input = GPU_shaderinterface_attr(shaderface, name); -#if TRUST_NO_ONE - assert(input != NULL); + int loc = GPU_shader_get_attribute(shader, name); /* TODO: make this a recoverable runtime error? * indicates mismatch between vertex format and program. */ -#endif - write_attr_location(binding, a_idx, input->location); + BLI_assert(loc != -1); + + write_attr_location(binding, a_idx, loc); } } } diff --git a/source/blender/gpu/intern/gpu_attr_binding_private.h b/source/blender/gpu/intern/gpu_attr_binding_private.h index 4d359343c38..cd67a51a822 100644 --- a/source/blender/gpu/intern/gpu_attr_binding_private.h +++ b/source/blender/gpu/intern/gpu_attr_binding_private.h @@ -25,8 +25,8 @@ #pragma once -#include "GPU_shader_interface.h" #include "GPU_vertex_format.h" +#include "gpu_shader_interface.hh" #ifdef __cplusplus extern "C" { @@ -35,9 +35,7 @@ extern "C" { /* TODO(fclem) remove, use shaderface directly. */ void AttrBinding_clear(GPUAttrBinding *binding); -void get_attr_locations(const GPUVertFormat *format, - GPUAttrBinding *binding, - const GPUShaderInterface *shaderface); +void get_attr_locations(const GPUVertFormat *format, GPUAttrBinding *binding, GPUShader *shader); uint read_attr_location(const GPUAttrBinding *binding, uint a_idx); #ifdef __cplusplus diff --git a/source/blender/gpu/intern/gpu_batch_private.hh b/source/blender/gpu/intern/gpu_batch_private.hh index 3a8044efc1d..11efd784238 100644 --- a/source/blender/gpu/intern/gpu_batch_private.hh +++ b/source/blender/gpu/intern/gpu_batch_private.hh @@ -28,7 +28,6 @@ #include "GPU_batch.h" #include "GPU_context.h" -#include "GPU_shader_interface.h" namespace blender { namespace gpu { diff --git a/source/blender/gpu/intern/gpu_immediate.cc b/source/blender/gpu/intern/gpu_immediate.cc index dd05689d69a..431dbe848f7 100644 --- a/source/blender/gpu/intern/gpu_immediate.cc +++ b/source/blender/gpu/intern/gpu_immediate.cc @@ -73,7 +73,6 @@ typedef struct { GLuint vao_id; GPUShader *bound_program; - const GPUShaderInterface *shader_interface; GPUAttrBinding attr_binding; uint16_t prev_enabled_attr_bits; /* <-- only affects this VAO, so we're ok */ } Immediate; @@ -148,14 +147,13 @@ void immBindShader(GPUShader *shader) BLI_assert(imm.bound_program == NULL); imm.bound_program = shader; - imm.shader_interface = shader->interface; if (!imm.vertex_format.packed) { VertexFormat_pack(&imm.vertex_format); } GPU_shader_bind(shader); - get_attr_locations(&imm.vertex_format, &imm.attr_binding, imm.shader_interface); + get_attr_locations(&imm.vertex_format, &imm.attr_binding, shader); GPU_matrix_bind(shader); GPU_shader_set_srgb_uniform(shader); } @@ -749,123 +747,77 @@ void immVertex2iv(uint attr_id, const int data[2]) /* --- generic uniform functions --- */ -#if 0 -# if TRUST_NO_ONE -# define GET_UNIFORM \ - const GPUShaderInput *uniform = GPU_shaderinterface_uniform(imm.shader_interface, name); \ - assert(uniform); -# else -# define GET_UNIFORM \ - const GPUShaderInput *uniform = GPU_shaderinterface_uniform(imm.shader_interface, name); -# endif -#else -/* NOTE: It is possible to have uniform fully optimized out from the shader. - * In this case we can't assert failure or allow NULL-pointer dereference. - * TODO(sergey): How can we detect existing-but-optimized-out uniform but still - * catch typos in uniform names passed to immUniform*() functions? */ -# define GET_UNIFORM \ - const GPUShaderInput *uniform = GPU_shaderinterface_uniform(imm.shader_interface, name); \ - if (uniform == NULL) \ - return; -#endif - void immUniform1f(const char *name, float x) { - GET_UNIFORM - glUniform1f(uniform->location, x); + GPU_shader_uniform_1f(imm.bound_program, name, x); } void immUniform2f(const char *name, float x, float y) { - GET_UNIFORM - glUniform2f(uniform->location, x, y); + GPU_shader_uniform_2f(imm.bound_program, name, x, y); } void immUniform2fv(const char *name, const float data[2]) { - GET_UNIFORM - glUniform2fv(uniform->location, 1, data); + GPU_shader_uniform_2fv(imm.bound_program, name, data); } void immUniform3f(const char *name, float x, float y, float z) { - GET_UNIFORM - glUniform3f(uniform->location, x, y, z); + GPU_shader_uniform_3f(imm.bound_program, name, x, y, z); } void immUniform3fv(const char *name, const float data[3]) { - GET_UNIFORM - glUniform3fv(uniform->location, 1, data); -} - -/* can increase this limit or move to another file */ -#define MAX_UNIFORM_NAME_LEN 60 - -/* Note array index is not supported for name (i.e: "array[0]"). */ -void immUniformArray3fv(const char *name, const float *data, int count) -{ - GET_UNIFORM - glUniform3fv(uniform->location, count, data); + GPU_shader_uniform_3fv(imm.bound_program, name, data); } void immUniform4f(const char *name, float x, float y, float z, float w) { - GET_UNIFORM - glUniform4f(uniform->location, x, y, z, w); + GPU_shader_uniform_4f(imm.bound_program, name, x, y, z, w); } void immUniform4fv(const char *name, const float data[4]) { - GET_UNIFORM - glUniform4fv(uniform->location, 1, data); + GPU_shader_uniform_4fv(imm.bound_program, name, data); } /* Note array index is not supported for name (i.e: "array[0]"). */ void immUniformArray4fv(const char *name, const float *data, int count) { - GET_UNIFORM - glUniform4fv(uniform->location, count, data); + GPU_shader_uniform_4fv_array(imm.bound_program, name, count, (float(*)[4])data); } void immUniformMatrix4fv(const char *name, const float data[4][4]) { - GET_UNIFORM - glUniformMatrix4fv(uniform->location, 1, GL_FALSE, (float *)data); + GPU_shader_uniform_mat4(imm.bound_program, name, data); } void immUniform1i(const char *name, int x) { - GET_UNIFORM - glUniform1i(uniform->location, x); -} - -void immUniform4iv(const char *name, const int data[4]) -{ - GET_UNIFORM - glUniform4iv(uniform->location, 1, data); + GPU_shader_uniform_1i(imm.bound_program, name, x); } void immBindTexture(const char *name, GPUTexture *tex) { - GET_UNIFORM - GPU_texture_bind(tex, uniform->binding); + int binding = GPU_shader_get_texture_binding(imm.bound_program, name); + GPU_texture_bind(tex, binding); } void immBindTextureSampler(const char *name, GPUTexture *tex, eGPUSamplerState state) { - GET_UNIFORM - GPU_texture_bind_ex(tex, state, uniform->binding, true); + int binding = GPU_shader_get_texture_binding(imm.bound_program, name); + GPU_texture_bind_ex(tex, state, binding, true); } /* --- convenience functions for setting "uniform vec4 color" --- */ void immUniformColor4f(float r, float g, float b, float a) { - int32_t uniform_loc = GPU_shaderinterface_uniform_builtin(imm.shader_interface, - GPU_UNIFORM_COLOR); + int32_t uniform_loc = GPU_shader_get_builtin_uniform(imm.bound_program, GPU_UNIFORM_COLOR); BLI_assert(uniform_loc != -1); - glUniform4f(uniform_loc, r, g, b, a); + float data[4] = {r, g, b, a}; + GPU_shader_uniform_vector(imm.bound_program, uniform_loc, 4, 1, data); } void immUniformColor4fv(const float rgba[4]) diff --git a/source/blender/gpu/intern/gpu_matrix.cc b/source/blender/gpu/intern/gpu_matrix.cc index 951652b9393..cdb6d303588 100644 --- a/source/blender/gpu/intern/gpu_matrix.cc +++ b/source/blender/gpu/intern/gpu_matrix.cc @@ -21,8 +21,6 @@ * \ingroup gpu */ -#include "GPU_shader_interface.h" - #include "gpu_context_private.hh" #include "gpu_matrix_private.h" @@ -649,14 +647,13 @@ void GPU_matrix_bind(GPUShader *shader) * call this before a draw call if desired matrices are dirty * call glUseProgram before this, as glUniform expects program to be bound */ - const GPUShaderInterface *shaderface = shader->interface; - int32_t MV = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_MODELVIEW); - int32_t P = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_PROJECTION); - int32_t MVP = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_MVP); - - int32_t N = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_NORMAL); - int32_t MV_inv = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_MODELVIEW_INV); - int32_t P_inv = GPU_shaderinterface_uniform_builtin(shaderface, GPU_UNIFORM_PROJECTION_INV); + int32_t MV = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODELVIEW); + int32_t P = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_PROJECTION); + int32_t MVP = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MVP); + + int32_t N = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_NORMAL); + int32_t MV_inv = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODELVIEW_INV); + int32_t P_inv = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_PROJECTION_INV); if (MV != -1) { GPU_shader_uniform_vector(shader, MV, 16, 1, (const float *)GPU_matrix_model_view_get(NULL)); diff --git a/source/blender/gpu/intern/gpu_select_pick.c b/source/blender/gpu/intern/gpu_select_pick.c index 29e2615345c..f7fd1faeb1e 100644 --- a/source/blender/gpu/intern/gpu_select_pick.c +++ b/source/blender/gpu/intern/gpu_select_pick.c @@ -27,6 +27,7 @@ #include <stdlib.h> #include <string.h> +#include "GPU_framebuffer.h" #include "GPU_glew.h" #include "GPU_immediate.h" #include "GPU_select.h" @@ -287,7 +288,7 @@ typedef struct GPUPickState { int viewport[4]; int scissor[4]; eGPUWriteMask write_mask; - bool depth_test; + eGPUDepthTest depth_test; } GPUPickState; static GPUPickState g_pick_state = {0}; @@ -311,18 +312,17 @@ void gpu_select_pick_begin(uint (*buffer)[4], uint bufsize, const rcti *input, c /* Restrict OpenGL operations for when we don't have cache */ if (ps->is_cached == false) { ps->write_mask = GPU_write_mask_get(); - ps->depth_test = GPU_depth_test_enabled(); + ps->depth_test = GPU_depth_test_get(); GPU_scissor_get(ps->scissor); /* disable writing to the framebuffer */ GPU_color_mask(false, false, false, false); - glEnable(GL_DEPTH_TEST); - glDepthMask(GL_TRUE); + GPU_depth_mask(true); /* Always use #GL_LEQUAL even though GPU_SELECT_PICK_ALL always clears the buffer. This is * because individual objects themselves might have sections that overlap and we need these * to have the correct distance information. */ - glDepthFunc(GL_LEQUAL); + GPU_depth_test(GPU_DEPTH_LESS_EQUAL); float viewport[4]; GPU_viewport_size_get_f(viewport); @@ -339,7 +339,7 @@ void gpu_select_pick_begin(uint (*buffer)[4], uint bufsize, const rcti *input, c /* It's possible we don't want to clear depth buffer, * so existing elements are masked by current z-buffer. */ - glClear(GL_DEPTH_BUFFER_BIT); + GPU_clear(GPU_DEPTH_BIT); /* scratch buffer (read new values here) */ ps->gl.rect_depth_test = depth_buf_malloc(rect_len); @@ -519,7 +519,7 @@ bool gpu_select_pick_load_id(uint id, bool end) if (g_pick_state.mode == GPU_SELECT_PICK_ALL) { /* we want new depths every time */ - glClear(GL_DEPTH_BUFFER_BIT); + GPU_clear(GPU_DEPTH_BIT); } } } diff --git a/source/blender/gpu/intern/gpu_select_sample_query.c b/source/blender/gpu/intern/gpu_select_sample_query.c index 62414febb44..7e41faf8678 100644 --- a/source/blender/gpu/intern/gpu_select_sample_query.c +++ b/source/blender/gpu/intern/gpu_select_sample_query.c @@ -26,6 +26,7 @@ #include <stdlib.h> +#include "GPU_framebuffer.h" #include "GPU_glew.h" #include "GPU_select.h" #include "GPU_state.h" @@ -65,7 +66,7 @@ typedef struct GPUQueryState { int viewport[4]; int scissor[4]; eGPUWriteMask write_mask; - bool depth_test; + eGPUDepthTest depth_test; } GPUQueryState; static GPUQueryState g_query_state = {0}; @@ -91,7 +92,7 @@ void gpu_select_query_begin( glGenQueries(g_query_state.num_of_queries, g_query_state.queries); g_query_state.write_mask = GPU_write_mask_get(); - g_query_state.depth_test = GPU_depth_test_enabled(); + g_query_state.depth_test = GPU_depth_test_get(); GPU_scissor_get(g_query_state.scissor); /* disable writing to the framebuffer */ @@ -112,20 +113,17 @@ void gpu_select_query_begin( if (mode == GPU_SELECT_ALL) { /* glQueries on Windows+Intel drivers only works with depth testing turned on. * See T62947 for details */ - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_ALWAYS); - glDepthMask(GL_TRUE); + GPU_depth_test(GPU_DEPTH_ALWAYS); + GPU_depth_mask(true); } else if (mode == GPU_SELECT_NEAREST_FIRST_PASS) { - glClear(GL_DEPTH_BUFFER_BIT); - glEnable(GL_DEPTH_TEST); - glDepthMask(GL_TRUE); - glDepthFunc(GL_LEQUAL); + GPU_clear(GPU_DEPTH_BIT); + GPU_depth_test(GPU_DEPTH_LESS_EQUAL); + GPU_depth_mask(true); } else if (mode == GPU_SELECT_NEAREST_SECOND_PASS) { - glEnable(GL_DEPTH_TEST); - glDepthMask(GL_FALSE); - glDepthFunc(GL_EQUAL); + GPU_depth_test(GPU_DEPTH_EQUAL); + GPU_depth_mask(false); } } diff --git a/source/blender/gpu/intern/gpu_shader.cc b/source/blender/gpu/intern/gpu_shader.cc index 4e74e1f69e7..9b4fe1d06ca 100644 --- a/source/blender/gpu/intern/gpu_shader.cc +++ b/source/blender/gpu/intern/gpu_shader.cc @@ -95,7 +95,7 @@ void Shader::print_errors(Span<const char *> sources, char *log) error_char = (int)strtol(error_line_number_end + 1, NULL, 10); } } - if ((error_line == -1)) { + if (error_line == -1) { found_line_id = false; } const char *src_line = sources_combined; @@ -196,8 +196,8 @@ Shader::Shader(const char *sh_name) Shader::~Shader() { - if (this->interface) { - GPU_shaderinterface_discard(this->interface); + if (interface) { + delete interface; } } @@ -484,43 +484,49 @@ void GPU_shader_transform_feedback_disable(GPUShader *shader) int GPU_shader_get_uniform(GPUShader *shader, const char *name) { - const GPUShaderInput *uniform = GPU_shaderinterface_uniform(shader->interface, name); + ShaderInterface *interface = static_cast<Shader *>(shader)->interface; + const ShaderInput *uniform = interface->uniform_get(name); return uniform ? uniform->location : -1; } int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin) { - return GPU_shaderinterface_uniform_builtin(shader->interface, - static_cast<GPUUniformBuiltin>(builtin)); + ShaderInterface *interface = static_cast<Shader *>(shader)->interface; + return interface->uniform_builtin((GPUUniformBuiltin)builtin); } int GPU_shader_get_builtin_block(GPUShader *shader, int builtin) { - return GPU_shaderinterface_block_builtin(shader->interface, - static_cast<GPUUniformBlockBuiltin>(builtin)); + ShaderInterface *interface = static_cast<Shader *>(shader)->interface; + return interface->ubo_builtin((GPUUniformBlockBuiltin)builtin); } +/* DEPRECATED. */ int GPU_shader_get_uniform_block(GPUShader *shader, const char *name) { - const GPUShaderInput *ubo = GPU_shaderinterface_ubo(shader->interface, name); + ShaderInterface *interface = static_cast<Shader *>(shader)->interface; + const ShaderInput *ubo = interface->ubo_get(name); return ubo ? ubo->location : -1; } int GPU_shader_get_uniform_block_binding(GPUShader *shader, const char *name) { - const GPUShaderInput *ubo = GPU_shaderinterface_ubo(shader->interface, name); + ShaderInterface *interface = static_cast<Shader *>(shader)->interface; + const ShaderInput *ubo = interface->ubo_get(name); return ubo ? ubo->binding : -1; } int GPU_shader_get_texture_binding(GPUShader *shader, const char *name) { - const GPUShaderInput *tex = GPU_shaderinterface_uniform(shader->interface, name); + ShaderInterface *interface = static_cast<Shader *>(shader)->interface; + const ShaderInput *tex = interface->uniform_get(name); return tex ? tex->binding : -1; } int GPU_shader_get_attribute(GPUShader *shader, const char *name) { - const GPUShaderInput *attr = GPU_shaderinterface_attr(shader->interface, name); + ShaderInterface *interface = static_cast<Shader *>(shader)->interface; + const ShaderInput *attr = interface->attr_get(name); return attr ? attr->location : -1; } @@ -565,14 +571,10 @@ void GPU_shader_uniform_float(GPUShader *shader, int location, float value) GPU_shader_uniform_vector(shader, location, 1, 1, &value); } -#define GET_UNIFORM \ - const GPUShaderInput *uniform = GPU_shaderinterface_uniform(sh->interface, name); \ - BLI_assert(uniform); - void GPU_shader_uniform_1i(GPUShader *sh, const char *name, int value) { - GET_UNIFORM - GPU_shader_uniform_int(sh, uniform->location, value); + const int loc = GPU_shader_get_uniform(sh, name); + GPU_shader_uniform_int(sh, loc, value); } void GPU_shader_uniform_1b(GPUShader *sh, const char *name, bool value) @@ -600,44 +602,44 @@ void GPU_shader_uniform_4f(GPUShader *sh, const char *name, float x, float y, fl void GPU_shader_uniform_1f(GPUShader *sh, const char *name, float x) { - GET_UNIFORM - GPU_shader_uniform_float(sh, uniform->location, x); + const int loc = GPU_shader_get_uniform(sh, name); + GPU_shader_uniform_float(sh, loc, x); } void GPU_shader_uniform_2fv(GPUShader *sh, const char *name, const float data[2]) { - GET_UNIFORM - GPU_shader_uniform_vector(sh, uniform->location, 2, 1, data); + const int loc = GPU_shader_get_uniform(sh, name); + GPU_shader_uniform_vector(sh, loc, 2, 1, data); } void GPU_shader_uniform_3fv(GPUShader *sh, const char *name, const float data[3]) { - GET_UNIFORM - GPU_shader_uniform_vector(sh, uniform->location, 3, 1, data); + const int loc = GPU_shader_get_uniform(sh, name); + GPU_shader_uniform_vector(sh, loc, 3, 1, data); } void GPU_shader_uniform_4fv(GPUShader *sh, const char *name, const float data[4]) { - GET_UNIFORM - GPU_shader_uniform_vector(sh, uniform->location, 4, 1, data); + const int loc = GPU_shader_get_uniform(sh, name); + GPU_shader_uniform_vector(sh, loc, 4, 1, data); } void GPU_shader_uniform_mat4(GPUShader *sh, const char *name, const float data[4][4]) { - GET_UNIFORM - GPU_shader_uniform_vector(sh, uniform->location, 16, 1, (const float *)data); + const int loc = GPU_shader_get_uniform(sh, name); + GPU_shader_uniform_vector(sh, loc, 16, 1, (const float *)data); } void GPU_shader_uniform_2fv_array(GPUShader *sh, const char *name, int len, const float (*val)[2]) { - GET_UNIFORM - GPU_shader_uniform_vector(sh, uniform->location, 2, len, (const float *)val); + const int loc = GPU_shader_get_uniform(sh, name); + GPU_shader_uniform_vector(sh, loc, 2, len, (const float *)val); } void GPU_shader_uniform_4fv_array(GPUShader *sh, const char *name, int len, const float (*val)[4]) { - GET_UNIFORM - GPU_shader_uniform_vector(sh, uniform->location, 4, len, (const float *)val); + const int loc = GPU_shader_get_uniform(sh, name); + GPU_shader_uniform_vector(sh, loc, 4, len, (const float *)val); } /** \} */ @@ -657,7 +659,7 @@ static int g_shader_builtin_srgb_transform = 0; void GPU_shader_set_srgb_uniform(GPUShader *shader) { - int32_t loc = GPU_shaderinterface_uniform_builtin(shader->interface, GPU_UNIFORM_SRGB_TRANSFORM); + int32_t loc = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_SRGB_TRANSFORM); if (loc != -1) { GPU_shader_uniform_vector_int(shader, loc, 1, 1, &g_shader_builtin_srgb_transform); } diff --git a/source/blender/gpu/intern/gpu_shader_interface.cc b/source/blender/gpu/intern/gpu_shader_interface.cc index ef90dde1877..dc59dca9f78 100644 --- a/source/blender/gpu/intern/gpu_shader_interface.cc +++ b/source/blender/gpu/intern/gpu_shader_interface.cc @@ -23,161 +23,41 @@ * GPU shader interface (C --> GLSL) */ -#include "BKE_global.h" - -#include "BLI_bitmap.h" -#include "BLI_math_base.h" - #include "MEM_guardedalloc.h" -#include "GPU_shader_interface.h" - -#include "gpu_batch_private.hh" -#include "gpu_context_private.hh" - -#include "gl_batch.hh" - -#include <stddef.h> -#include <stdlib.h> -#include <string.h> - -#define DEBUG_SHADER_INTERFACE 0 - -#if DEBUG_SHADER_INTERFACE -# include <stdio.h> -#endif - -using namespace blender::gpu; - -static const char *BuiltinUniform_name(GPUUniformBuiltin u) -{ - switch (u) { - case GPU_UNIFORM_MODEL: - return "ModelMatrix"; - case GPU_UNIFORM_VIEW: - return "ViewMatrix"; - case GPU_UNIFORM_MODELVIEW: - return "ModelViewMatrix"; - case GPU_UNIFORM_PROJECTION: - return "ProjectionMatrix"; - case GPU_UNIFORM_VIEWPROJECTION: - return "ViewProjectionMatrix"; - case GPU_UNIFORM_MVP: - return "ModelViewProjectionMatrix"; - - case GPU_UNIFORM_MODEL_INV: - return "ModelMatrixInverse"; - case GPU_UNIFORM_VIEW_INV: - return "ViewMatrixInverse"; - case GPU_UNIFORM_MODELVIEW_INV: - return "ModelViewMatrixInverse"; - case GPU_UNIFORM_PROJECTION_INV: - return "ProjectionMatrixInverse"; - case GPU_UNIFORM_VIEWPROJECTION_INV: - return "ViewProjectionMatrixInverse"; - - case GPU_UNIFORM_NORMAL: - return "NormalMatrix"; - case GPU_UNIFORM_ORCO: - return "OrcoTexCoFactors"; - case GPU_UNIFORM_CLIPPLANES: - return "WorldClipPlanes"; - - case GPU_UNIFORM_COLOR: - return "color"; - case GPU_UNIFORM_BASE_INSTANCE: - return "baseInstance"; - case GPU_UNIFORM_RESOURCE_CHUNK: - return "resourceChunk"; - case GPU_UNIFORM_RESOURCE_ID: - return "resourceId"; - case GPU_UNIFORM_SRGB_TRANSFORM: - return "srgbTarget"; +#include "BLI_span.hh" +#include "BLI_vector.hh" - default: - return NULL; - } -} +#include "gpu_shader_interface.hh" -static const char *BuiltinUniformBlock_name(GPUUniformBlockBuiltin u) -{ - switch (u) { - case GPU_UNIFORM_BLOCK_VIEW: - return "viewBlock"; - case GPU_UNIFORM_BLOCK_MODEL: - return "modelBlock"; - case GPU_UNIFORM_BLOCK_INFO: - return "infoBlock"; - default: - return NULL; - } -} +namespace blender::gpu { -GPU_INLINE bool match(const char *a, const char *b) +ShaderInterface::ShaderInterface(void) { - return STREQ(a, b); + /* TODO(fclem) add unique ID for debugging. */ } -GPU_INLINE uint hash_string(const char *str) +ShaderInterface::~ShaderInterface(void) { - uint i = 0, c; - while ((c = *str++)) { - i = i * 37 + c; - } - return i; + /* Free memory used by name_buffer. */ + MEM_freeN(name_buffer_); + MEM_freeN(inputs_); } -GPU_INLINE uint32_t set_input_name(GPUShaderInterface *shaderface, - GPUShaderInput *input, - char *name, - uint32_t name_len) +static void sort_input_list(MutableSpan<ShaderInput> dst) { - /* remove "[0]" from array name */ - if (name[name_len - 1] == ']') { - name[name_len - 3] = '\0'; - name_len -= 3; + if (dst.size() == 0) { + return; } - input->name_offset = (uint32_t)(name - shaderface->name_buffer); - input->name_hash = hash_string(name); - return name_len + 1; /* include NULL terminator */ -} - -GPU_INLINE const GPUShaderInput *input_lookup(const GPUShaderInterface *shaderface, - const GPUShaderInput *const inputs, - const uint inputs_len, - const char *name) -{ - const uint name_hash = hash_string(name); - /* Simple linear search for now. */ - for (int i = inputs_len - 1; i >= 0; i--) { - if (inputs[i].name_hash == name_hash) { - if ((i > 0) && UNLIKELY(inputs[i - 1].name_hash == name_hash)) { - /* Hash colision resolve. */ - for (; i >= 0 && inputs[i].name_hash == name_hash; i--) { - if (match(name, shaderface->name_buffer + inputs[i].name_offset)) { - return inputs + i; /* not found */ - } - } - return NULL; /* not found */ - } - - /* This is a bit dangerous since we could have a hash collision. - * where the asked uniform that does not exist has the same hash - * as a real uniform. */ - BLI_assert(match(name, shaderface->name_buffer + inputs[i].name_offset)); - return inputs + i; - } - } - return NULL; /* not found */ -} + Vector<ShaderInput> inputs_vec = Vector<ShaderInput>(dst.size()); + MutableSpan<ShaderInput> src = inputs_vec.as_mutable_span(); + src.copy_from(dst); -/* Note that this modify the src array. */ -GPU_INLINE void sort_input_list(GPUShaderInput *dst, GPUShaderInput *src, const uint input_len) -{ - for (uint i = 0; i < input_len; i++) { - GPUShaderInput *input_src = &src[0]; - for (uint j = 1; j < input_len; j++) { + /* Simple sorting by going through the array and selecting the biggest element each time. */ + for (uint i = 0; i < dst.size(); i++) { + ShaderInput *input_src = &src[0]; + for (uint j = 1; j < src.size(); j++) { if (src[j].name_hash > input_src->name_hash) { input_src = &src[j]; } @@ -187,360 +67,60 @@ GPU_INLINE void sort_input_list(GPUShaderInput *dst, GPUShaderInput *src, const } } -static int block_binding(int32_t program, uint32_t block_index) +/* Sorts all inputs inside their respective array. + * This is to allow fast hash collision detection. + * See ShaderInterface::input_lookup for more details. */ +void ShaderInterface::sort_inputs(void) { - /* For now just assign a consecutive index. In the future, we should set it in - * the shader using layout(binding = i) and query its value. */ - glUniformBlockBinding(program, block_index, block_index); - return block_index; + sort_input_list(MutableSpan<ShaderInput>(inputs_, attr_len_)); + sort_input_list(MutableSpan<ShaderInput>(inputs_ + attr_len_, ubo_len_)); + sort_input_list(MutableSpan<ShaderInput>(inputs_ + attr_len_ + ubo_len_, uniform_len_)); } -static int sampler_binding(int32_t program, - uint32_t uniform_index, - int32_t uniform_location, - int *sampler_len) +void ShaderInterface::debug_print(void) { - /* Identify sampler uniforms and asign sampler units to them. */ - GLint type; - glGetActiveUniformsiv(program, 1, &uniform_index, GL_UNIFORM_TYPE, &type); - - switch (type) { - case GL_SAMPLER_1D: - case GL_SAMPLER_2D: - case GL_SAMPLER_3D: - case GL_SAMPLER_CUBE: - case GL_SAMPLER_CUBE_MAP_ARRAY_ARB: /* OpenGL 4.0 */ - case GL_SAMPLER_1D_SHADOW: - case GL_SAMPLER_2D_SHADOW: - case GL_SAMPLER_1D_ARRAY: - case GL_SAMPLER_2D_ARRAY: - case GL_SAMPLER_1D_ARRAY_SHADOW: - case GL_SAMPLER_2D_ARRAY_SHADOW: - case GL_SAMPLER_2D_MULTISAMPLE: - case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: - case GL_SAMPLER_CUBE_SHADOW: - case GL_SAMPLER_BUFFER: - case GL_INT_SAMPLER_1D: - case GL_INT_SAMPLER_2D: - case GL_INT_SAMPLER_3D: - case GL_INT_SAMPLER_CUBE: - case GL_INT_SAMPLER_1D_ARRAY: - case GL_INT_SAMPLER_2D_ARRAY: - case GL_INT_SAMPLER_2D_MULTISAMPLE: - case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: - case GL_INT_SAMPLER_BUFFER: - case GL_UNSIGNED_INT_SAMPLER_1D: - case GL_UNSIGNED_INT_SAMPLER_2D: - case GL_UNSIGNED_INT_SAMPLER_3D: - case GL_UNSIGNED_INT_SAMPLER_CUBE: - case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: - case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: - case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: - case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: - case GL_UNSIGNED_INT_SAMPLER_BUFFER: { - /* For now just assign a consecutive index. In the future, we should set it in - * the shader using layout(binding = i) and query its value. */ - int binding = *sampler_len; - glUniform1i(uniform_location, binding); - (*sampler_len)++; - return binding; - } - default: - return -1; - } -} + Span<ShaderInput> attrs = Span<ShaderInput>(inputs_, attr_len_); + Span<ShaderInput> ubos = Span<ShaderInput>(inputs_ + attr_len_, ubo_len_); + Span<ShaderInput> uniforms = Span<ShaderInput>(inputs_ + attr_len_ + ubo_len_, uniform_len_); + char *name_buf = name_buffer_; + const char format[] = " | %.8x : %4d : %s\n"; -GPUShaderInterface *GPU_shaderinterface_create(int32_t program) -{ -#ifndef NDEBUG - GLint curr_program; - glGetIntegerv(GL_CURRENT_PROGRAM, &curr_program); - BLI_assert(curr_program == program); -#endif - - GLint max_attr_name_len = 0, attr_len = 0; - glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_attr_name_len); - glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &attr_len); - - GLint max_ubo_name_len = 0, ubo_len = 0; - glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &max_ubo_name_len); - glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &ubo_len); - - GLint max_uniform_name_len = 0, active_uniform_len = 0, uniform_len = 0; - glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_uniform_name_len); - glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &active_uniform_len); - uniform_len = active_uniform_len; - - /* Work around driver bug with Intel HD 4600 on Windows 7/8, where - * GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH does not work. */ - if (attr_len > 0 && max_attr_name_len == 0) { - max_attr_name_len = 256; - } - if (ubo_len > 0 && max_ubo_name_len == 0) { - max_ubo_name_len = 256; + printf(" \033[1mGPUShaderInterface : \033[0m\n"); + if (attrs.size() > 0) { + printf("\n Attributes :\n"); } - if (uniform_len > 0 && max_uniform_name_len == 0) { - max_uniform_name_len = 256; + for (const ShaderInput &attr : attrs) { + printf(format, attr.name_hash, attr.location, name_buf + attr.name_offset); } - /* GL_ACTIVE_UNIFORMS lied to us! Remove the UBO uniforms from the total before - * allocating the uniform array. */ - GLint max_ubo_uni_len = 0; - for (int i = 0; i < ubo_len; i++) { - GLint ubo_uni_len; - glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &ubo_uni_len); - max_ubo_uni_len = max_ii(max_ubo_uni_len, ubo_uni_len); - uniform_len -= ubo_uni_len; + if (uniforms.size() > 0) { + printf("\n Uniforms :\n"); } - /* Bit set to true if uniform comes from a uniform block. */ - BLI_bitmap *uniforms_from_blocks = BLI_BITMAP_NEW(active_uniform_len, __func__); - /* Set uniforms from block for exclusion. */ - GLint *ubo_uni_ids = (GLint *)MEM_mallocN(sizeof(GLint) * max_ubo_uni_len, __func__); - for (int i = 0; i < ubo_len; i++) { - GLint ubo_uni_len; - glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &ubo_uni_len); - glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, ubo_uni_ids); - for (int u = 0; u < ubo_uni_len; u++) { - BLI_BITMAP_ENABLE(uniforms_from_blocks, ubo_uni_ids[u]); + for (const ShaderInput &uni : uniforms) { + /* Bypass samplers. */ + if (uni.binding == -1) { + printf(format, uni.name_hash, uni.location, name_buf + uni.name_offset); } } - MEM_freeN(ubo_uni_ids); - uint32_t name_buffer_offset = 0; - const uint32_t name_buffer_len = attr_len * max_attr_name_len + ubo_len * max_ubo_name_len + - uniform_len * max_uniform_name_len; - - int input_tot_len = attr_len + ubo_len + uniform_len; - size_t interface_size = sizeof(GPUShaderInterface) + sizeof(GPUShaderInput) * input_tot_len; - - GPUShaderInterface *shaderface = (GPUShaderInterface *)MEM_callocN(interface_size, - "GPUShaderInterface"); - shaderface->attribute_len = attr_len; - shaderface->ubo_len = ubo_len; - shaderface->uniform_len = uniform_len; - shaderface->name_buffer = (char *)MEM_mallocN(name_buffer_len, "name_buffer"); - GPUShaderInput *inputs = shaderface->inputs; - - /* Temp buffer. */ - int input_tmp_len = max_iii(attr_len, ubo_len, uniform_len); - GPUShaderInput *inputs_tmp = (GPUShaderInput *)MEM_mallocN( - sizeof(GPUShaderInput) * input_tmp_len, "name_buffer"); - - /* Attributes */ - shaderface->enabled_attr_mask = 0; - for (int i = 0, idx = 0; i < attr_len; i++) { - char *name = shaderface->name_buffer + name_buffer_offset; - GLsizei remaining_buffer = name_buffer_len - name_buffer_offset; - GLsizei name_len = 0; - GLenum type; - GLint size; - - glGetActiveAttrib(program, i, remaining_buffer, &name_len, &size, &type, name); - GLint location = glGetAttribLocation(program, name); - /* Ignore OpenGL names like `gl_BaseInstanceARB`, `gl_InstanceID` and `gl_VertexID`. */ - if (location == -1) { - shaderface->attribute_len--; - continue; - } - - GPUShaderInput *input = &inputs_tmp[idx++]; - input->location = input->binding = location; - - name_buffer_offset += set_input_name(shaderface, input, name, name_len); - shaderface->enabled_attr_mask |= (1 << input->location); + if (ubos.size() > 0) { + printf("\n Uniform Buffer Objects :\n"); } - sort_input_list(inputs, inputs_tmp, shaderface->attribute_len); - inputs += shaderface->attribute_len; - - /* Uniform Blocks */ - for (int i = 0, idx = 0; i < ubo_len; i++) { - char *name = shaderface->name_buffer + name_buffer_offset; - GLsizei remaining_buffer = name_buffer_len - name_buffer_offset; - GLsizei name_len = 0; - - glGetActiveUniformBlockName(program, i, remaining_buffer, &name_len, name); - - GPUShaderInput *input = &inputs_tmp[idx++]; - input->binding = input->location = block_binding(program, i); - - name_buffer_offset += set_input_name(shaderface, input, name, name_len); - shaderface->enabled_ubo_mask |= (1 << input->binding); + for (const ShaderInput &ubo : ubos) { + printf(format, ubo.name_hash, ubo.binding, name_buf + ubo.name_offset); } - sort_input_list(inputs, inputs_tmp, shaderface->ubo_len); - inputs += shaderface->ubo_len; - /* Uniforms */ - for (int i = 0, idx = 0, sampler = 0; i < active_uniform_len; i++) { - if (BLI_BITMAP_TEST(uniforms_from_blocks, i)) { - continue; - } - char *name = shaderface->name_buffer + name_buffer_offset; - GLsizei remaining_buffer = name_buffer_len - name_buffer_offset; - GLsizei name_len = 0; - - glGetActiveUniformName(program, i, remaining_buffer, &name_len, name); - - GPUShaderInput *input = &inputs_tmp[idx++]; - input->location = glGetUniformLocation(program, name); - input->binding = sampler_binding(program, i, input->location, &sampler); - - name_buffer_offset += set_input_name(shaderface, input, name, name_len); - shaderface->enabled_tex_mask |= (input->binding != -1) ? (1lu << input->binding) : 0lu; - } - sort_input_list(inputs, inputs_tmp, shaderface->uniform_len); - - /* Builtin Uniforms */ - for (int32_t u_int = 0; u_int < GPU_NUM_UNIFORMS; u_int++) { - GPUUniformBuiltin u = static_cast<GPUUniformBuiltin>(u_int); - shaderface->builtins[u] = glGetUniformLocation(program, BuiltinUniform_name(u)); - } - - /* Builtin Uniforms Blocks */ - for (int32_t u_int = 0; u_int < GPU_NUM_UNIFORM_BLOCKS; u_int++) { - GPUUniformBlockBuiltin u = static_cast<GPUUniformBlockBuiltin>(u_int); - const GPUShaderInput *block = GPU_shaderinterface_ubo(shaderface, BuiltinUniformBlock_name(u)); - shaderface->builtin_blocks[u] = (block != NULL) ? block->binding : -1; - } - - /* Batches ref buffer */ - shaderface->batches_len = GPU_SHADERINTERFACE_REF_ALLOC_COUNT; - shaderface->batches = (void **)MEM_callocN(shaderface->batches_len * sizeof(GPUBatch *), - "GPUShaderInterface batches"); - - MEM_freeN(uniforms_from_blocks); - MEM_freeN(inputs_tmp); - - /* Resize name buffer to save some memory. */ - if (name_buffer_offset < name_buffer_len) { - shaderface->name_buffer = (char *)MEM_reallocN(shaderface->name_buffer, name_buffer_offset); - } - -#if DEBUG_SHADER_INTERFACE - char *name_buf = shaderface->name_buffer; - printf("--- GPUShaderInterface %p, program %d ---\n", shaderface, program); - if (shaderface->attribute_len > 0) { - printf("Attributes {\n"); - for (int i = 0; i < shaderface->attribute_len; i++) { - GPUShaderInput *input = shaderface->inputs + i; - printf("\t(location = %d) %s;\n", input->location, name_buf + input->name_offset); - } - printf("};\n"); - } - if (shaderface->ubo_len > 0) { - printf("Uniform Buffer Objects {\n"); - for (int i = 0; i < shaderface->ubo_len; i++) { - GPUShaderInput *input = shaderface->inputs + shaderface->attribute_len + i; - printf("\t(binding = %d) %s;\n", input->binding, name_buf + input->name_offset); - } - printf("};\n"); + if (enabled_tex_mask_ > 0) { + printf("\n Samplers :\n"); } - if (shaderface->enabled_tex_mask > 0) { - printf("Samplers {\n"); - for (int i = 0; i < shaderface->uniform_len; i++) { - GPUShaderInput *input = shaderface->inputs + shaderface->attribute_len + - shaderface->ubo_len + i; - if (input->binding != -1) { - printf("\t(location = %d, binding = %d) %s;\n", - input->location, - input->binding, - name_buf + input->name_offset); - } - } - printf("};\n"); - } - if (shaderface->uniform_len > 0) { - printf("Uniforms {\n"); - for (int i = 0; i < shaderface->uniform_len; i++) { - GPUShaderInput *input = shaderface->inputs + shaderface->attribute_len + - shaderface->ubo_len + i; - if (input->binding == -1) { - printf("\t(location = %d) %s;\n", input->location, name_buf + input->name_offset); - } + for (const ShaderInput &samp : uniforms) { + /* Bypass uniforms. */ + if (samp.binding != -1) { + printf(format, samp.name_hash, samp.binding, name_buf + samp.name_offset); } - printf("};\n"); } - printf("--- GPUShaderInterface end ---\n\n"); -#endif - return shaderface; -} - -void GPU_shaderinterface_discard(GPUShaderInterface *shaderface) -{ - /* Free memory used by name_buffer. */ - MEM_freeN(shaderface->name_buffer); - /* Remove this interface from all linked Batches vao cache. */ - for (int i = 0; i < shaderface->batches_len; i++) { - if (shaderface->batches[i] != NULL) { - /* XXX GL specific. to be removed during refactor. */ - reinterpret_cast<GLVaoCache *>(shaderface->batches[i])->remove(shaderface); - } - } - MEM_freeN(shaderface->batches); - /* Free memory used by shader interface by its self. */ - MEM_freeN(shaderface); + printf("\n"); } -const GPUShaderInput *GPU_shaderinterface_attr(const GPUShaderInterface *shaderface, - const char *name) -{ - uint ofs = 0; - return input_lookup(shaderface, shaderface->inputs + ofs, shaderface->attribute_len, name); -} - -const GPUShaderInput *GPU_shaderinterface_ubo(const GPUShaderInterface *shaderface, - const char *name) -{ - uint ofs = shaderface->attribute_len; - return input_lookup(shaderface, shaderface->inputs + ofs, shaderface->ubo_len, name); -} - -const GPUShaderInput *GPU_shaderinterface_uniform(const GPUShaderInterface *shaderface, - const char *name) -{ - uint ofs = shaderface->attribute_len + shaderface->ubo_len; - return input_lookup(shaderface, shaderface->inputs + ofs, shaderface->uniform_len, name); -} - -int32_t GPU_shaderinterface_uniform_builtin(const GPUShaderInterface *shaderface, - GPUUniformBuiltin builtin) -{ - BLI_assert(builtin >= 0 && builtin < GPU_NUM_UNIFORMS); - return shaderface->builtins[builtin]; -} - -int32_t GPU_shaderinterface_block_builtin(const GPUShaderInterface *shaderface, - GPUUniformBlockBuiltin builtin) -{ - BLI_assert(builtin >= 0 && builtin < GPU_NUM_UNIFORM_BLOCKS); - return shaderface->builtin_blocks[builtin]; -} - -void GPU_shaderinterface_add_batch_ref(GPUShaderInterface *shaderface, void *batch) -{ - int i; /* find first unused slot */ - for (i = 0; i < shaderface->batches_len; i++) { - if (shaderface->batches[i] == NULL) { - break; - } - } - if (i == shaderface->batches_len) { - /* Not enough place, realloc the array. */ - i = shaderface->batches_len; - shaderface->batches_len += GPU_SHADERINTERFACE_REF_ALLOC_COUNT; - shaderface->batches = (void **)MEM_recallocN(shaderface->batches, - sizeof(void *) * shaderface->batches_len); - } - /** XXX todo cleanup. */ - shaderface->batches[i] = reinterpret_cast<void *>(batch); -} - -void GPU_shaderinterface_remove_batch_ref(GPUShaderInterface *shaderface, void *batch) -{ - for (int i = 0; i < shaderface->batches_len; i++) { - if (shaderface->batches[i] == batch) { - shaderface->batches[i] = NULL; - break; /* cannot have duplicates */ - } - } -} +} // namespace blender::gpu diff --git a/source/blender/gpu/intern/gpu_shader_interface.hh b/source/blender/gpu/intern/gpu_shader_interface.hh new file mode 100644 index 00000000000..76925f4fddb --- /dev/null +++ b/source/blender/gpu/intern/gpu_shader_interface.hh @@ -0,0 +1,225 @@ +/* + * 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) 2016 by Mike Erwin. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + * + * GPU shader interface (C --> GLSL) + * + * Structure detailling needed vertex inputs and resources for a specific shader. + * A shader interface can be shared between two similar shaders. + */ + +#pragma once + +#include <cstring> /* required for STREQ later on. */ + +#include "BLI_hash.h" +#include "BLI_utildefines.h" + +#include "GPU_shader.h" + +namespace blender::gpu { + +typedef struct ShaderInput { + uint32_t name_offset; + uint32_t name_hash; + int32_t location; + /** Defined at interface creation or in shader. Only for Samplers, UBOs and Vertex Attribs. */ + int32_t binding; +} ShaderInput; + +class ShaderInterface { + /* TODO(fclem) should be protected. */ + public: + /** Flat array. In this order: Attributes, Ubos, Uniforms. */ + ShaderInput *inputs_ = NULL; + /** Buffer containing all inputs names separated by '\0'. */ + char *name_buffer_ = NULL; + /** Input counts inside input array. */ + uint attr_len_ = 0; + uint ubo_len_ = 0; + uint uniform_len_ = 0; + /** Enabled bindpoints that needs to be fed with data. */ + uint16_t enabled_attr_mask_ = 0; + uint16_t enabled_ubo_mask_ = 0; + uint64_t enabled_tex_mask_ = 0; + /** Location of builtin uniforms. Fast access, no lookup needed. */ + int32_t builtins_[GPU_NUM_UNIFORMS]; + int32_t builtin_blocks_[GPU_NUM_UNIFORM_BLOCKS]; + + public: + ShaderInterface(); + virtual ~ShaderInterface(); + + void debug_print(void); + + inline const ShaderInput *attr_get(const char *name) const + { + return input_lookup(inputs_, attr_len_, name); + } + + inline const ShaderInput *ubo_get(const char *name) const + { + return input_lookup(inputs_ + attr_len_, ubo_len_, name); + } + + inline const ShaderInput *uniform_get(const char *name) const + { + return input_lookup(inputs_ + attr_len_ + ubo_len_, uniform_len_, name); + } + + /* Returns uniform location. */ + inline int32_t uniform_builtin(const GPUUniformBuiltin builtin) const + { + BLI_assert(builtin >= 0 && builtin < GPU_NUM_UNIFORMS); + return builtins_[builtin]; + } + + /* Returns binding position. */ + inline int32_t ubo_builtin(const GPUUniformBlockBuiltin builtin) const + { + BLI_assert(builtin >= 0 && builtin < GPU_NUM_UNIFORM_BLOCKS); + return builtin_blocks_[builtin]; + } + + protected: + static inline const char *builtin_uniform_name(GPUUniformBuiltin u); + static inline const char *builtin_uniform_block_name(GPUUniformBlockBuiltin u); + + inline uint32_t set_input_name(ShaderInput *input, char *name, uint32_t name_len) const; + + /* Finalize interface construction by sorting the ShaderInputs for faster lookups. */ + void sort_inputs(void); + + private: + inline const ShaderInput *input_lookup(const ShaderInput *const inputs, + const uint inputs_len, + const char *name) const; +}; + +inline const char *ShaderInterface::builtin_uniform_name(GPUUniformBuiltin u) +{ + switch (u) { + case GPU_UNIFORM_MODEL: + return "ModelMatrix"; + case GPU_UNIFORM_VIEW: + return "ViewMatrix"; + case GPU_UNIFORM_MODELVIEW: + return "ModelViewMatrix"; + case GPU_UNIFORM_PROJECTION: + return "ProjectionMatrix"; + case GPU_UNIFORM_VIEWPROJECTION: + return "ViewProjectionMatrix"; + case GPU_UNIFORM_MVP: + return "ModelViewProjectionMatrix"; + + case GPU_UNIFORM_MODEL_INV: + return "ModelMatrixInverse"; + case GPU_UNIFORM_VIEW_INV: + return "ViewMatrixInverse"; + case GPU_UNIFORM_MODELVIEW_INV: + return "ModelViewMatrixInverse"; + case GPU_UNIFORM_PROJECTION_INV: + return "ProjectionMatrixInverse"; + case GPU_UNIFORM_VIEWPROJECTION_INV: + return "ViewProjectionMatrixInverse"; + + case GPU_UNIFORM_NORMAL: + return "NormalMatrix"; + case GPU_UNIFORM_ORCO: + return "OrcoTexCoFactors"; + case GPU_UNIFORM_CLIPPLANES: + return "WorldClipPlanes"; + + case GPU_UNIFORM_COLOR: + return "color"; + case GPU_UNIFORM_BASE_INSTANCE: + return "baseInstance"; + case GPU_UNIFORM_RESOURCE_CHUNK: + return "resourceChunk"; + case GPU_UNIFORM_RESOURCE_ID: + return "resourceId"; + case GPU_UNIFORM_SRGB_TRANSFORM: + return "srgbTarget"; + + default: + return NULL; + } +} + +inline const char *ShaderInterface::builtin_uniform_block_name(GPUUniformBlockBuiltin u) +{ + switch (u) { + case GPU_UNIFORM_BLOCK_VIEW: + return "viewBlock"; + case GPU_UNIFORM_BLOCK_MODEL: + return "modelBlock"; + case GPU_UNIFORM_BLOCK_INFO: + return "infoBlock"; + default: + return NULL; + } +} + +/* Returns string length including '\0' terminator. */ +inline uint32_t ShaderInterface::set_input_name(ShaderInput *input, + char *name, + uint32_t name_len) const +{ + /* remove "[0]" from array name */ + if (name[name_len - 1] == ']') { + name[name_len - 3] = '\0'; + name_len -= 3; + } + + input->name_offset = (uint32_t)(name - name_buffer_); + input->name_hash = BLI_hash_string(name); + return name_len + 1; /* include NULL terminator */ +} + +inline const ShaderInput *ShaderInterface::input_lookup(const ShaderInput *const inputs, + const uint inputs_len, + const char *name) const +{ + const uint name_hash = BLI_hash_string(name); + /* Simple linear search for now. */ + for (int i = inputs_len - 1; i >= 0; i--) { + if (inputs[i].name_hash == name_hash) { + if ((i > 0) && UNLIKELY(inputs[i - 1].name_hash == name_hash)) { + /* Hash colision resolve. */ + for (; i >= 0 && inputs[i].name_hash == name_hash; i--) { + if (STREQ(name, name_buffer_ + inputs[i].name_offset)) { + return inputs + i; /* not found */ + } + } + return NULL; /* not found */ + } + + /* This is a bit dangerous since we could have a hash collision. + * where the asked uniform that does not exist has the same hash + * as a real uniform. */ + BLI_assert(STREQ(name, name_buffer_ + inputs[i].name_offset)); + return inputs + i; + } + } + return NULL; /* not found */ +} + +} // namespace blender::gpu diff --git a/source/blender/gpu/intern/gpu_shader_private.hh b/source/blender/gpu/intern/gpu_shader_private.hh index 1f667fb4cf9..d51c3b03ecb 100644 --- a/source/blender/gpu/intern/gpu_shader_private.hh +++ b/source/blender/gpu/intern/gpu_shader_private.hh @@ -23,14 +23,18 @@ #include "BLI_span.hh" #include "GPU_shader.h" -#include "GPU_shader_interface.h" #include "GPU_vertex_buffer.h" +#include "gpu_shader_interface.hh" namespace blender { namespace gpu { class Shader : public GPUShader { public: + /** Uniform & attribute locations for shader. */ + ShaderInterface *interface; + + public: Shader(const char *name); virtual ~Shader(); diff --git a/source/blender/gpu/intern/gpu_state.cc b/source/blender/gpu/intern/gpu_state.cc index f02ec9c5cd4..1be3b06fa34 100644 --- a/source/blender/gpu/intern/gpu_state.cc +++ b/source/blender/gpu/intern/gpu_state.cc @@ -44,7 +44,7 @@ using namespace blender::gpu; do { \ GPUStateManager *stack = GPU_context_active_get()->state_manager; \ auto &state_object = stack->_prefix##state; \ - state_object._state = _value; \ + state_object._state = (_value); \ } while (0) #define SET_IMMUTABLE_STATE(_state, _value) SET_STATE(, _state, _value) @@ -74,10 +74,9 @@ void GPU_provoking_vertex(eGPUProvokingVertex vert) SET_IMMUTABLE_STATE(provoking_vert, vert); } -/* TODO explicit depth test. */ -void GPU_depth_test(bool enable) +void GPU_depth_test(eGPUDepthTest test) { - SET_IMMUTABLE_STATE(depth_test, (enable) ? GPU_DEPTH_LESS_EQUAL : GPU_DEPTH_NONE); + SET_IMMUTABLE_STATE(depth_test, test); } void GPU_line_smooth(bool enable) @@ -104,11 +103,11 @@ void GPU_color_mask(bool r, bool g, bool b, bool a) { GPUStateManager *stack = GPU_context_active_get()->state_manager; auto &state = stack->state; - eGPUWriteMask write_mask = state.write_mask; - SET_FLAG_FROM_TEST(write_mask, r, GPU_WRITE_RED); - SET_FLAG_FROM_TEST(write_mask, g, GPU_WRITE_GREEN); - SET_FLAG_FROM_TEST(write_mask, b, GPU_WRITE_BLUE); - SET_FLAG_FROM_TEST(write_mask, a, GPU_WRITE_ALPHA); + uint32_t write_mask = state.write_mask; + SET_FLAG_FROM_TEST(write_mask, r, (uint32_t)GPU_WRITE_RED); + SET_FLAG_FROM_TEST(write_mask, g, (uint32_t)GPU_WRITE_GREEN); + SET_FLAG_FROM_TEST(write_mask, b, (uint32_t)GPU_WRITE_BLUE); + SET_FLAG_FROM_TEST(write_mask, a, (uint32_t)GPU_WRITE_ALPHA); state.write_mask = write_mask; } @@ -116,8 +115,8 @@ void GPU_depth_mask(bool depth) { GPUStateManager *stack = GPU_context_active_get()->state_manager; auto &state = stack->state; - eGPUWriteMask write_mask = state.write_mask; - SET_FLAG_FROM_TEST(write_mask, depth, GPU_WRITE_DEPTH); + uint32_t write_mask = state.write_mask; + SET_FLAG_FROM_TEST(write_mask, depth, (uint32_t)GPU_WRITE_DEPTH); state.write_mask = write_mask; } @@ -141,13 +140,13 @@ void GPU_state_set(eGPUWriteMask write_mask, { GPUStateManager *stack = GPU_context_active_get()->state_manager; auto &state = stack->state; - state.write_mask = write_mask; - state.blend = blend; - state.culling_test = culling_test; - state.depth_test = depth_test; - state.stencil_test = stencil_test; - state.stencil_op = stencil_op; - state.provoking_vert = provoking_vert; + state.write_mask = (uint32_t)write_mask; + state.blend = (uint32_t)blend; + state.culling_test = (uint32_t)culling_test; + state.depth_test = (uint32_t)depth_test; + state.stencil_test = (uint32_t)stencil_test; + state.stencil_op = (uint32_t)stencil_op; + state.provoking_vert = (uint32_t)provoking_vert; } /** \} */ @@ -231,19 +230,19 @@ void GPU_stencil_compare_mask_set(uint compare_mask) eGPUBlend GPU_blend_get() { GPUState &state = GPU_context_active_get()->state_manager->state; - return state.blend; + return (eGPUBlend)state.blend; } eGPUWriteMask GPU_write_mask_get() { GPUState &state = GPU_context_active_get()->state_manager->state; - return state.write_mask; + return (eGPUWriteMask)state.write_mask; } -bool GPU_depth_test_enabled() +eGPUDepthTest GPU_depth_test_get() { GPUState &state = GPU_context_active_get()->state_manager->state; - return state.depth_test != GPU_DEPTH_NONE; + return (eGPUDepthTest)state.depth_test; } void GPU_scissor_get(int coords[4]) diff --git a/source/blender/gpu/intern/gpu_state_private.hh b/source/blender/gpu/intern/gpu_state_private.hh index 99f580de15e..f325f035f28 100644 --- a/source/blender/gpu/intern/gpu_state_private.hh +++ b/source/blender/gpu/intern/gpu_state_private.hh @@ -31,17 +31,24 @@ namespace blender { namespace gpu { -/* Ecapsulate all pipeline state that we need to track. +/* Encapsulate all pipeline state that we need to track. * Try to keep small to reduce validation time. */ union GPUState { struct { - eGPUWriteMask write_mask : 13; - eGPUBlend blend : 4; - eGPUFaceCullTest culling_test : 2; - eGPUDepthTest depth_test : 3; - eGPUStencilTest stencil_test : 3; - eGPUStencilOp stencil_op : 3; - eGPUProvokingVertex provoking_vert : 1; + /** eGPUWriteMask */ + uint32_t write_mask : 13; + /** eGPUBlend */ + uint32_t blend : 4; + /** eGPUFaceCullTest */ + uint32_t culling_test : 2; + /** eGPUDepthTest */ + uint32_t depth_test : 3; + /** eGPUStencilTest */ + uint32_t stencil_test : 3; + /** eGPUStencilOp */ + uint32_t stencil_op : 3; + /** eGPUProvokingVertex */ + uint32_t provoking_vert : 1; /** Enable bits. */ uint32_t logic_op_xor : 1; uint32_t invert_facing : 1; diff --git a/source/blender/gpu/opengl/gl_batch.cc b/source/blender/gpu/opengl/gl_batch.cc index fade8763065..9ca0a9f71db 100644 --- a/source/blender/gpu/opengl/gl_batch.cc +++ b/source/blender/gpu/opengl/gl_batch.cc @@ -33,6 +33,7 @@ #include "gpu_batch_private.hh" #include "gpu_primitive_private.h" +#include "gpu_shader_private.hh" #include "gl_batch.hh" #include "gl_context.hh" @@ -71,7 +72,7 @@ void GLVaoCache::init(void) } /* Create a new VAO object and store it in the cache. */ -void GLVaoCache::insert(const GPUShaderInterface *interface, GLuint vao) +void GLVaoCache::insert(const GLShaderInterface *interface, GLuint vao) { /* Now insert the cache. */ if (!is_dynamic_vao_count) { @@ -90,8 +91,7 @@ void GLVaoCache::insert(const GPUShaderInterface *interface, GLuint vao) /* Erase previous entries, they will be added back if drawn again. */ for (int i = 0; i < GPU_VAO_STATIC_LEN; i++) { if (static_vaos.interfaces[i] != NULL) { - GPU_shaderinterface_remove_batch_ref( - const_cast<GPUShaderInterface *>(static_vaos.interfaces[i]), this); + const_cast<GLShaderInterface *>(static_vaos.interfaces[i])->ref_remove(this); context_->vao_free(static_vaos.vao_ids[i]); } } @@ -99,8 +99,8 @@ void GLVaoCache::insert(const GPUShaderInterface *interface, GLuint vao) is_dynamic_vao_count = true; /* Init dynamic arrays and let the branch below set the values. */ dynamic_vaos.count = GPU_BATCH_VAO_DYN_ALLOC_COUNT; - dynamic_vaos.interfaces = (const GPUShaderInterface **)MEM_callocN( - dynamic_vaos.count * sizeof(GPUShaderInterface *), "dyn vaos interfaces"); + dynamic_vaos.interfaces = (const GLShaderInterface **)MEM_callocN( + dynamic_vaos.count * sizeof(GLShaderInterface *), "dyn vaos interfaces"); dynamic_vaos.vao_ids = (GLuint *)MEM_callocN(dynamic_vaos.count * sizeof(GLuint), "dyn vaos ids"); } @@ -118,8 +118,8 @@ void GLVaoCache::insert(const GPUShaderInterface *interface, GLuint vao) /* Not enough place, realloc the array. */ i = dynamic_vaos.count; dynamic_vaos.count += GPU_BATCH_VAO_DYN_ALLOC_COUNT; - dynamic_vaos.interfaces = (const GPUShaderInterface **)MEM_recallocN( - (void *)dynamic_vaos.interfaces, sizeof(GPUShaderInterface *) * dynamic_vaos.count); + dynamic_vaos.interfaces = (const GLShaderInterface **)MEM_recallocN( + (void *)dynamic_vaos.interfaces, sizeof(GLShaderInterface *) * dynamic_vaos.count); dynamic_vaos.vao_ids = (GLuint *)MEM_recallocN(dynamic_vaos.vao_ids, sizeof(GLuint) * dynamic_vaos.count); } @@ -127,15 +127,15 @@ void GLVaoCache::insert(const GPUShaderInterface *interface, GLuint vao) dynamic_vaos.vao_ids[i] = vao; } - GPU_shaderinterface_add_batch_ref(const_cast<GPUShaderInterface *>(interface), this); + const_cast<GLShaderInterface *>(interface)->ref_add(this); } -void GLVaoCache::remove(const GPUShaderInterface *interface) +void GLVaoCache::remove(const GLShaderInterface *interface) { const int count = (is_dynamic_vao_count) ? dynamic_vaos.count : GPU_VAO_STATIC_LEN; GLuint *vaos = (is_dynamic_vao_count) ? dynamic_vaos.vao_ids : static_vaos.vao_ids; - const GPUShaderInterface **interfaces = (is_dynamic_vao_count) ? dynamic_vaos.interfaces : - static_vaos.interfaces; + const GLShaderInterface **interfaces = (is_dynamic_vao_count) ? dynamic_vaos.interfaces : + static_vaos.interfaces; for (int i = 0; i < count; i++) { if (interfaces[i] == interface) { context_->vao_free(vaos[i]); @@ -151,8 +151,8 @@ void GLVaoCache::clear(void) GLContext *ctx = static_cast<GLContext *>(GPU_context_active_get()); const int count = (is_dynamic_vao_count) ? dynamic_vaos.count : GPU_VAO_STATIC_LEN; GLuint *vaos = (is_dynamic_vao_count) ? dynamic_vaos.vao_ids : static_vaos.vao_ids; - const GPUShaderInterface **interfaces = (is_dynamic_vao_count) ? dynamic_vaos.interfaces : - static_vaos.interfaces; + const GLShaderInterface **interfaces = (is_dynamic_vao_count) ? dynamic_vaos.interfaces : + static_vaos.interfaces; /* Early out, nothing to free. */ if (context_ == NULL) { return; @@ -171,10 +171,9 @@ void GLVaoCache::clear(void) } for (int i = 0; i < count; i++) { - if (interfaces[i] == NULL) { - continue; + if (interfaces[i] != NULL) { + const_cast<GLShaderInterface *>(interfaces[i])->ref_remove(this); } - GPU_shaderinterface_remove_batch_ref(const_cast<GPUShaderInterface *>(interfaces[i]), this); } if (is_dynamic_vao_count) { @@ -190,11 +189,11 @@ void GLVaoCache::clear(void) } /* Return 0 on cache miss (invalid VAO) */ -GLuint GLVaoCache::lookup(const GPUShaderInterface *interface) +GLuint GLVaoCache::lookup(const GLShaderInterface *interface) { const int count = (is_dynamic_vao_count) ? dynamic_vaos.count : GPU_VAO_STATIC_LEN; - const GPUShaderInterface **interfaces = (is_dynamic_vao_count) ? dynamic_vaos.interfaces : - static_vaos.interfaces; + const GLShaderInterface **interfaces = (is_dynamic_vao_count) ? dynamic_vaos.interfaces : + static_vaos.interfaces; for (int i = 0; i < count; i++) { if (interfaces[i] == interface) { return (is_dynamic_vao_count) ? dynamic_vaos.vao_ids[i] : static_vaos.vao_ids[i]; @@ -226,7 +225,9 @@ GLuint GLVaoCache::base_instance_vao_get(GPUBatch *batch, int i_first) { this->context_check(); /* Make sure the interface is up to date. */ - if (interface_ != GPU_context_active_get()->shader->interface) { + Shader *shader = static_cast<Shader *>(GPU_context_active_get()->shader); + GLShaderInterface *interface = static_cast<GLShaderInterface *>(shader->interface); + if (interface_ != interface) { vao_get(batch); /* Trigger update. */ base_instance_ = 0; @@ -255,9 +256,10 @@ GLuint GLVaoCache::vao_get(GPUBatch *batch) { this->context_check(); - GPUContext *ctx = GPU_context_active_get(); - if (interface_ != ctx->shader->interface) { - interface_ = ctx->shader->interface; + Shader *shader = static_cast<Shader *>(GPU_context_active_get()->shader); + GLShaderInterface *interface = static_cast<GLShaderInterface *>(shader->interface); + if (interface_ != interface) { + interface_ = interface; vao_id_ = this->lookup(interface_); if (vao_id_ == 0) { diff --git a/source/blender/gpu/opengl/gl_batch.hh b/source/blender/gpu/opengl/gl_batch.hh index d70f43aed2a..9a7767d679d 100644 --- a/source/blender/gpu/opengl/gl_batch.hh +++ b/source/blender/gpu/opengl/gl_batch.hh @@ -32,11 +32,11 @@ #include "glew-mx.h" -#include "GPU_shader_interface.h" - namespace blender { namespace gpu { +class GLShaderInterface; + #define GPU_VAO_STATIC_LEN 3 /* Vao management: remembers all geometry state (vertex attribute bindings & element buffer) @@ -47,7 +47,7 @@ class GLVaoCache { /** Context for which the vao_cache_ was generated. */ struct GLContext *context_ = NULL; /** Last interface this batch was drawn with. */ - GPUShaderInterface *interface_ = NULL; + GLShaderInterface *interface_ = NULL; /** Cached vao for the last interface. */ GLuint vao_id_ = 0; /** Used whend arb_base_instance is not supported. */ @@ -58,13 +58,13 @@ class GLVaoCache { union { /** Static handle count */ struct { - const GPUShaderInterface *interfaces[GPU_VAO_STATIC_LEN]; + const GLShaderInterface *interfaces[GPU_VAO_STATIC_LEN]; GLuint vao_ids[GPU_VAO_STATIC_LEN]; } static_vaos; /** Dynamic handle count */ struct { uint count; - const GPUShaderInterface **interfaces; + const GLShaderInterface **interfaces; GLuint *vao_ids; } dynamic_vaos; }; @@ -76,9 +76,9 @@ class GLVaoCache { GLuint vao_get(GPUBatch *batch); GLuint base_instance_vao_get(GPUBatch *batch, int i_first); - GLuint lookup(const GPUShaderInterface *interface); - void insert(const GPUShaderInterface *interface, GLuint vao_id); - void remove(const GPUShaderInterface *interface); + GLuint lookup(const GLShaderInterface *interface); + void insert(const GLShaderInterface *interface, GLuint vao_id); + void remove(const GLShaderInterface *interface); void clear(void); private: diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc index ea33ff00d69..93ed7a408c6 100644 --- a/source/blender/gpu/opengl/gl_shader.cc +++ b/source/blender/gpu/opengl/gl_shader.cc @@ -29,6 +29,7 @@ #include "GPU_platform.h" #include "gl_shader.hh" +#include "gl_shader_interface.hh" using namespace blender; using namespace blender::gpu; @@ -203,10 +204,7 @@ bool GLShader::finalize(void) return false; } - /* TODO(fclem) We need this to modify the image binding points using glUniform. - * This could be avoided using glProgramUniform in GL 4.1. */ - glUseProgram(shader_program_); - interface = GPU_shaderinterface_create(shader_program_); + interface = new GLShaderInterface(shader_program_); return true; } diff --git a/source/blender/gpu/opengl/gl_shader.hh b/source/blender/gpu/opengl/gl_shader.hh index 0e37ea18d23..b432a04abaa 100644 --- a/source/blender/gpu/opengl/gl_shader.hh +++ b/source/blender/gpu/opengl/gl_shader.hh @@ -57,7 +57,7 @@ class GLShader : public Shader { bool finalize(void) override; void transform_feedback_names_set(Span<const char *> name_list, - const eGPUShaderTFBType geom_type); + const eGPUShaderTFBType geom_type) override; bool transform_feedback_enable(GPUVertBuf *buf) override; void transform_feedback_disable(void) override; diff --git a/source/blender/gpu/opengl/gl_shader_interface.cc b/source/blender/gpu/opengl/gl_shader_interface.cc new file mode 100644 index 00000000000..423db5c8c97 --- /dev/null +++ b/source/blender/gpu/opengl/gl_shader_interface.cc @@ -0,0 +1,297 @@ +/* + * 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) 2016 by Mike Erwin. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + * + * GPU shader interface (C --> GLSL) + */ + +#include "BLI_bitmap.h" + +#include "gl_batch.hh" + +#include "gl_shader_interface.hh" + +namespace blender::gpu { + +/* -------------------------------------------------------------------- */ +/** \name Binding assignment + * + * To mimic vulkan, we assign binding at shader creation to avoid shader recompilation. + * In the future, we should set it in the shader using layout(binding = i) and query its value. + * \{ */ + +static inline int block_binding(int32_t program, uint32_t block_index) +{ + /* For now just assign a consecutive index. In the future, we should set it in + * the shader using layout(binding = i) and query its value. */ + glUniformBlockBinding(program, block_index, block_index); + return block_index; +} + +static inline int sampler_binding(int32_t program, + uint32_t uniform_index, + int32_t uniform_location, + int *sampler_len) +{ + /* Identify sampler uniforms and asign sampler units to them. */ + GLint type; + glGetActiveUniformsiv(program, 1, &uniform_index, GL_UNIFORM_TYPE, &type); + + switch (type) { + case GL_SAMPLER_1D: + case GL_SAMPLER_2D: + case GL_SAMPLER_3D: + case GL_SAMPLER_CUBE: + case GL_SAMPLER_CUBE_MAP_ARRAY_ARB: /* OpenGL 4.0 */ + case GL_SAMPLER_1D_SHADOW: + case GL_SAMPLER_2D_SHADOW: + case GL_SAMPLER_1D_ARRAY: + case GL_SAMPLER_2D_ARRAY: + case GL_SAMPLER_1D_ARRAY_SHADOW: + case GL_SAMPLER_2D_ARRAY_SHADOW: + case GL_SAMPLER_2D_MULTISAMPLE: + case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: + case GL_SAMPLER_CUBE_SHADOW: + case GL_SAMPLER_BUFFER: + case GL_INT_SAMPLER_1D: + case GL_INT_SAMPLER_2D: + case GL_INT_SAMPLER_3D: + case GL_INT_SAMPLER_CUBE: + case GL_INT_SAMPLER_1D_ARRAY: + case GL_INT_SAMPLER_2D_ARRAY: + case GL_INT_SAMPLER_2D_MULTISAMPLE: + case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: + case GL_INT_SAMPLER_BUFFER: + case GL_UNSIGNED_INT_SAMPLER_1D: + case GL_UNSIGNED_INT_SAMPLER_2D: + case GL_UNSIGNED_INT_SAMPLER_3D: + case GL_UNSIGNED_INT_SAMPLER_CUBE: + case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: + case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_BUFFER: { + /* For now just assign a consecutive index. In the future, we should set it in + * the shader using layout(binding = i) and query its value. */ + int binding = *sampler_len; + glUniform1i(uniform_location, binding); + (*sampler_len)++; + return binding; + } + default: + return -1; + } +} +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Creation / Destruction + * \{ */ + +GLShaderInterface::GLShaderInterface(GLuint program) +{ + /* Necessary to make glUniform works. */ + glUseProgram(program); + + GLint max_attr_name_len = 0, attr_len = 0; + glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_attr_name_len); + glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &attr_len); + + GLint max_ubo_name_len = 0, ubo_len = 0; + glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &max_ubo_name_len); + glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &ubo_len); + + GLint max_uniform_name_len = 0, active_uniform_len = 0, uniform_len = 0; + glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_uniform_name_len); + glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &active_uniform_len); + uniform_len = active_uniform_len; + + /* Work around driver bug with Intel HD 4600 on Windows 7/8, where + * GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH does not work. */ + if (attr_len > 0 && max_attr_name_len == 0) { + max_attr_name_len = 256; + } + if (ubo_len > 0 && max_ubo_name_len == 0) { + max_ubo_name_len = 256; + } + if (uniform_len > 0 && max_uniform_name_len == 0) { + max_uniform_name_len = 256; + } + + /* GL_ACTIVE_UNIFORMS lied to us! Remove the UBO uniforms from the total before + * allocating the uniform array. */ + GLint max_ubo_uni_len = 0; + for (int i = 0; i < ubo_len; i++) { + GLint ubo_uni_len; + glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &ubo_uni_len); + max_ubo_uni_len = max_ii(max_ubo_uni_len, ubo_uni_len); + uniform_len -= ubo_uni_len; + } + /* Bit set to true if uniform comes from a uniform block. */ + BLI_bitmap *uniforms_from_blocks = BLI_BITMAP_NEW(active_uniform_len, __func__); + /* Set uniforms from block for exclusion. */ + GLint *ubo_uni_ids = (GLint *)MEM_mallocN(sizeof(GLint) * max_ubo_uni_len, __func__); + for (int i = 0; i < ubo_len; i++) { + GLint ubo_uni_len; + glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &ubo_uni_len); + glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, ubo_uni_ids); + for (int u = 0; u < ubo_uni_len; u++) { + BLI_BITMAP_ENABLE(uniforms_from_blocks, ubo_uni_ids[u]); + } + } + MEM_freeN(ubo_uni_ids); + + int input_tot_len = attr_len + ubo_len + uniform_len; + inputs_ = (ShaderInput *)MEM_callocN(sizeof(ShaderInput) * input_tot_len, __func__); + + const uint32_t name_buffer_len = attr_len * max_attr_name_len + ubo_len * max_ubo_name_len + + uniform_len * max_uniform_name_len; + name_buffer_ = (char *)MEM_mallocN(name_buffer_len, "name_buffer"); + uint32_t name_buffer_offset = 0; + + /* Attributes */ + enabled_attr_mask_ = 0; + for (int i = 0; i < attr_len; i++) { + char *name = name_buffer_ + name_buffer_offset; + GLsizei remaining_buffer = name_buffer_len - name_buffer_offset; + GLsizei name_len = 0; + GLenum type; + GLint size; + + glGetActiveAttrib(program, i, remaining_buffer, &name_len, &size, &type, name); + GLint location = glGetAttribLocation(program, name); + /* Ignore OpenGL names like `gl_BaseInstanceARB`, `gl_InstanceID` and `gl_VertexID`. */ + if (location == -1) { + continue; + } + + ShaderInput *input = &inputs_[attr_len_++]; + input->location = input->binding = location; + + name_buffer_offset += set_input_name(input, name, name_len); + enabled_attr_mask_ |= (1 << input->location); + } + + /* Uniform Blocks */ + for (int i = 0; i < ubo_len; i++) { + char *name = name_buffer_ + name_buffer_offset; + GLsizei remaining_buffer = name_buffer_len - name_buffer_offset; + GLsizei name_len = 0; + + glGetActiveUniformBlockName(program, i, remaining_buffer, &name_len, name); + + ShaderInput *input = &inputs_[attr_len_ + ubo_len_++]; + input->binding = input->location = block_binding(program, i); + + name_buffer_offset += this->set_input_name(input, name, name_len); + enabled_ubo_mask_ |= (1 << input->binding); + } + + /* Uniforms */ + for (int i = 0, sampler = 0; i < active_uniform_len; i++) { + if (BLI_BITMAP_TEST(uniforms_from_blocks, i)) { + continue; + } + char *name = name_buffer_ + name_buffer_offset; + GLsizei remaining_buffer = name_buffer_len - name_buffer_offset; + GLsizei name_len = 0; + + glGetActiveUniformName(program, i, remaining_buffer, &name_len, name); + + ShaderInput *input = &inputs_[attr_len_ + ubo_len_ + uniform_len_++]; + input->location = glGetUniformLocation(program, name); + input->binding = sampler_binding(program, i, input->location, &sampler); + + name_buffer_offset += this->set_input_name(input, name, name_len); + enabled_tex_mask_ |= (input->binding != -1) ? (1lu << input->binding) : 0lu; + } + + /* Builtin Uniforms */ + for (int32_t u_int = 0; u_int < GPU_NUM_UNIFORMS; u_int++) { + GPUUniformBuiltin u = static_cast<GPUUniformBuiltin>(u_int); + builtins_[u] = glGetUniformLocation(program, builtin_uniform_name(u)); + } + + /* Builtin Uniforms Blocks */ + for (int32_t u_int = 0; u_int < GPU_NUM_UNIFORM_BLOCKS; u_int++) { + GPUUniformBlockBuiltin u = static_cast<GPUUniformBlockBuiltin>(u_int); + const ShaderInput *block = this->ubo_get(builtin_uniform_block_name(u)); + builtin_blocks_[u] = (block != NULL) ? block->binding : -1; + } + + MEM_freeN(uniforms_from_blocks); + + /* Resize name buffer to save some memory. */ + if (name_buffer_offset < name_buffer_len) { + name_buffer_ = (char *)MEM_reallocN(name_buffer_, name_buffer_offset); + } + + // this->debug_print(); + + this->sort_inputs(); +} + +GLShaderInterface::~GLShaderInterface() +{ + for (auto *ref : refs_) { + if (ref != NULL) { + ref->remove(this); + } + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Batch Reference + * \{ */ + +void GLShaderInterface::ref_add(GLVaoCache *ref) +{ + for (int i = 0; i < refs_.size(); i++) { + if (refs_[i] == NULL) { + refs_[i] = ref; + return; + } + } + refs_.append(ref); +} + +void GLShaderInterface::ref_remove(GLVaoCache *ref) +{ + for (int i = 0; i < refs_.size(); i++) { + if (refs_[i] == ref) { + refs_[i] = NULL; + break; /* cannot have duplicates */ + } + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Validation + * TODO + * \{ */ + +/** \} */ + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/opengl/gl_shader_interface.hh b/source/blender/gpu/opengl/gl_shader_interface.hh new file mode 100644 index 00000000000..fdf9512ef79 --- /dev/null +++ b/source/blender/gpu/opengl/gl_shader_interface.hh @@ -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) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + * + * GPU shader interface (C --> GLSL) + * + * Structure detailling needed vertex inputs and resources for a specific shader. + * A shader interface can be shared between two similar shaders. + */ + +#pragma once + +#include "MEM_guardedalloc.h" + +#include "BLI_vector.hh" + +#include "glew-mx.h" + +#include "gpu_shader_interface.hh" + +namespace blender::gpu { + +class GLVaoCache; + +class GLShaderInterface : public ShaderInterface { + private: + /** Reference to VaoCaches using this interface */ + Vector<GLVaoCache *> refs_; + + public: + GLShaderInterface(GLuint program); + ~GLShaderInterface(); + + void ref_add(GLVaoCache *ref); + void ref_remove(GLVaoCache *ref); + + // bool resource_binding_validate(); + + MEM_CXX_CLASS_ALLOC_FUNCS("GLShaderInterface"); +}; + +} // namespace blender::gpu diff --git a/source/blender/gpu/opengl/gl_state.cc b/source/blender/gpu/opengl/gl_state.cc index 3e3695e0b48..4e21ab43b45 100644 --- a/source/blender/gpu/opengl/gl_state.cc +++ b/source/blender/gpu/opengl/gl_state.cc @@ -65,23 +65,23 @@ void GLStateManager::set_state(const GPUState &state) GPUState changed = state ^ current_; if (changed.blend != 0) { - set_blend(state.blend); + set_blend((eGPUBlend)state.blend); } if (changed.write_mask != 0) { - set_write_mask(state.write_mask); + set_write_mask((eGPUWriteMask)state.write_mask); } if (changed.depth_test != 0) { - set_depth_test(state.depth_test); + set_depth_test((eGPUDepthTest)state.depth_test); } if (changed.stencil_test != 0 || changed.stencil_op != 0) { - set_stencil_test(state.stencil_test, state.stencil_op); - set_stencil_mask(state.stencil_test, mutable_state); + set_stencil_test((eGPUStencilTest)state.stencil_test, (eGPUStencilOp)state.stencil_op); + set_stencil_mask((eGPUStencilTest)state.stencil_test, mutable_state); } if (changed.clip_distances != 0) { set_clip_distances(state.clip_distances, current_.clip_distances); } if (changed.culling_test != 0) { - set_backface_culling(state.culling_test); + set_backface_culling((eGPUFaceCullTest)state.culling_test); } if (changed.logic_op_xor != 0) { set_logic_op(state.logic_op_xor); @@ -90,7 +90,7 @@ void GLStateManager::set_state(const GPUState &state) set_facing(state.invert_facing); } if (changed.provoking_vert != 0) { - set_provoking_vert(state.provoking_vert); + set_provoking_vert((eGPUProvokingVertex)state.provoking_vert); } if (changed.shadow_bias != 0) { set_shadow_bias(state.shadow_bias); @@ -160,7 +160,7 @@ void GLStateManager::set_mutable_state(const GPUStateMutable &state) if (changed.stencil_compare_mask != 0 || changed.stencil_reference != 0 || changed.stencil_write_mask != 0) { - set_stencil_mask(current_.stencil_test, state); + set_stencil_mask((eGPUStencilTest)current_.stencil_test, state); } current_mutable_ = state; diff --git a/source/blender/gpu/opengl/gl_vertex_array.cc b/source/blender/gpu/opengl/gl_vertex_array.cc index 907dc37e46f..b2d2445f113 100644 --- a/source/blender/gpu/opengl/gl_vertex_array.cc +++ b/source/blender/gpu/opengl/gl_vertex_array.cc @@ -23,9 +23,9 @@ #include "GPU_glew.h" -#include "GPU_shader_interface.h" #include "GPU_vertex_buffer.h" +#include "gpu_shader_interface.hh" #include "gpu_vertex_format_private.h" #include "gl_batch.hh" @@ -33,14 +33,14 @@ #include "gl_vertex_array.hh" -using namespace blender::gpu; +namespace blender::gpu { /* -------------------------------------------------------------------- */ /** \name Vertex Array Bindings * \{ */ /* Returns enabled vertex pointers as a bitflag (one bit per attrib). */ -static uint16_t vbo_bind(const GPUShaderInterface *interface, +static uint16_t vbo_bind(const ShaderInterface *interface, const GPUVertFormat *format, uint v_first, uint v_len, @@ -68,7 +68,7 @@ static uint16_t vbo_bind(const GPUShaderInterface *interface, for (uint n_idx = 0; n_idx < a->name_len; n_idx++) { const char *name = GPU_vertformat_attr_name_get(format, a, n_idx); - const GPUShaderInput *input = GPU_shaderinterface_attr(interface, name); + const ShaderInput *input = interface->attr_get(name); if (input == NULL) { continue; @@ -111,10 +111,10 @@ static uint16_t vbo_bind(const GPUShaderInterface *interface, /* Update the Attrib Binding of the currently bound VAO. */ void GLVertArray::update_bindings(const GLuint vao, const GPUBatch *batch, - const GPUShaderInterface *interface, + const ShaderInterface *interface, const int base_instance) { - uint16_t attr_mask = interface->enabled_attr_mask; + uint16_t attr_mask = interface->enabled_attr_mask_; glBindVertexArray(vao); @@ -156,3 +156,5 @@ void GLVertArray::update_bindings(const GLuint vao, } /** \} */ + +} // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/opengl/gl_vertex_array.hh b/source/blender/gpu/opengl/gl_vertex_array.hh index 6da414d7e62..59cd50ad7b8 100644 --- a/source/blender/gpu/opengl/gl_vertex_array.hh +++ b/source/blender/gpu/opengl/gl_vertex_array.hh @@ -26,7 +26,7 @@ #include "glew-mx.h" #include "GPU_batch.h" -#include "GPU_shader_interface.h" +#include "gl_shader_interface.hh" namespace blender { namespace gpu { @@ -35,7 +35,7 @@ namespace GLVertArray { void update_bindings(const GLuint vao, const GPUBatch *batch, - const GPUShaderInterface *interface, + const ShaderInterface *interface, const int base_instance); } // namespace GLVertArray diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index feda4ba43eb..e16a22f5459 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -686,10 +686,6 @@ typedef enum IDRecalcFlag { ID_RECALC_PARAMETERS = (1 << 21), - /* Makes it so everything what depends on time. - * Basically, the same what changing frame in a timeline will do. */ - ID_RECALC_TIME = (1 << 22), - /* Input has changed and datablock is to be reload from disk. * Applies to movie clips to inform that copy-on-written version is to be refreshed for the new * input file or for color space changes. */ diff --git a/source/blender/makesdna/DNA_outliner_types.h b/source/blender/makesdna/DNA_outliner_types.h index 46c8b1570e3..24634412a55 100644 --- a/source/blender/makesdna/DNA_outliner_types.h +++ b/source/blender/makesdna/DNA_outliner_types.h @@ -109,6 +109,8 @@ enum { #define TSE_SCENE_COLLECTION_BASE 39 #define TSE_VIEW_COLLECTION_BASE 40 #define TSE_SCENE_OBJECTS_BASE 41 +#define TSE_EFFECT_BASE 42 +#define TSE_EFFECT 43 /* Check whether given TreeStoreElem should have a real ID in its ->id member. */ #define TSE_IS_REAL_ID(_tse) \ diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h index 7ff96c5a908..8e4063b36eb 100644 --- a/source/blender/makesdna/DNA_screen_types.h +++ b/source/blender/makesdna/DNA_screen_types.h @@ -68,8 +68,6 @@ typedef struct bScreen { /** User-setting for which editors get redrawn during anim playback. */ short redraws_flag; - char statusbar_info[256]; - /** Temp screen in a temp window, don't save (like user prefs). */ char temp; /** Temp screen for image render display or fileselect. */ @@ -536,9 +534,8 @@ typedef enum eScreen_Redraws_Flag { /** #Panel.flag */ enum { PNL_SELECT = (1 << 0), - PNL_CLOSEDX = (1 << 1), - PNL_CLOSEDY = (1 << 2), - PNL_CLOSED = (PNL_CLOSEDX | PNL_CLOSEDY), + PNL_UNUSED_1 = (1 << 1), /* Cleared */ + PNL_CLOSED = (1 << 2), /* PNL_TABBED = (1 << 3), */ /*UNUSED*/ /* PNL_OVERLAP = (1 << 4), */ /*UNUSED*/ PNL_PIN = (1 << 5), diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index ad1635ba0c0..9a88a9181f1 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -274,6 +274,9 @@ typedef struct SpaceOutliner { * Pointers to treestore elements, grouped by (id, type, nr) * in hashtable for faster searching */ void *treehash; + + char sort_method; + char _pad[7]; } SpaceOutliner; /* SpaceOutliner.flag */ @@ -282,8 +285,9 @@ typedef enum eSpaceOutliner_Flag { /* SO_NEWSELECTED = (1 << 1), */ /* UNUSED */ SO_FLAG_UNUSED_1 = (1 << 2), /* cleared */ /* SO_HIDE_KEYINGSETINFO = (1 << 3), */ /* UNUSED */ - SO_SKIP_SORT_ALPHA = (1 << 4), + /* SO_SKIP_SORT_ALPHA = (1 << 4), */ /* UNUSED */ SO_SYNC_SELECT = (1 << 5), + SO_MODE_COLUMN = (1 << 6), } eSpaceOutliner_Flag; /* SpaceOutliner.filter */ @@ -294,7 +298,7 @@ typedef enum eSpaceOutliner_Filter { SO_FILTER_NO_OB_CONTENT = (1 << 3), /* Not only mesh, but modifiers, constraints, ... */ SO_FILTER_NO_CHILDREN = (1 << 4), - SO_FILTER_UNUSED_5 = (1 << 5), /* cleared */ + SO_FILTER_NO_ROW_CHILDREN = (1 << 5), SO_FILTER_NO_OB_MESH = (1 << 6), SO_FILTER_NO_OB_ARMATURE = (1 << 7), SO_FILTER_NO_OB_EMPTY = (1 << 8), @@ -321,8 +325,8 @@ typedef enum eSpaceOutliner_Filter { SO_FILTER_OB_STATE_ACTIVE) #define SO_FILTER_ANY \ - (SO_FILTER_NO_OB_CONTENT | SO_FILTER_NO_CHILDREN | SO_FILTER_OB_TYPE | SO_FILTER_OB_STATE | \ - SO_FILTER_NO_COLLECTION) + (SO_FILTER_NO_OB_CONTENT | SO_FILTER_NO_CHILDREN | SO_FILTER_NO_ROW_CHILDREN | \ + SO_FILTER_OB_TYPE | SO_FILTER_OB_STATE | SO_FILTER_NO_COLLECTION) /* SpaceOutliner.filter_state */ typedef enum eSpaceOutliner_StateFilter { @@ -381,6 +385,13 @@ typedef enum eSpaceOutliner_Search_Flags { SO_SEARCH_RECURSIVE = (1 << 2), } eSpaceOutliner_Search_Flags; +/* SpaceOutliner.sort_method */ +typedef enum eSpaceOutliner_Sort_Types { + SO_SORT_FREE, + SO_SORT_ALPHA, + SO_SORT_TYPE, +} eSpaceOutliner_Sort_Types; + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index d34f431c848..2b1e5b3c702 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -599,7 +599,7 @@ static void rna_float_print(FILE *f, float num) else if (num == FLT_MAX) { fprintf(f, "FLT_MAX"); } - else if ((fabsf(num) < INT64_MAX) && ((int64_t)num == num)) { + else if ((fabsf(num) < (float)INT64_MAX) && ((int64_t)num == num)) { fprintf(f, "%.1ff", num); } else { diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index fa48cf2f399..f48a7e6715d 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -45,6 +45,7 @@ static const EnumPropertyItem prop_direction_items[] = { {0, NULL, 0, NULL, NULL}, }; +#ifdef RNA_RUNTIME static const EnumPropertyItem prop_smooth_direction_items[] = { {0, "SMOOTH", ICON_ADD, "Smooth", "Smooth the surfae"}, {BRUSH_DIR_IN, @@ -54,6 +55,7 @@ static const EnumPropertyItem prop_smooth_direction_items[] = { "Enhance the surface detail"}, {0, NULL, 0, NULL, NULL}, }; +#endif static const EnumPropertyItem sculpt_stroke_method_items[] = { {0, "DOTS", 0, "Dots", "Apply paint on each mouse move step"}, diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index c8d16ab65cc..9bcf2b81557 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -106,7 +106,7 @@ static const EnumPropertyItem rna_enum_keyframe_type_items[] = { }; static const EnumPropertyItem rna_enum_onion_keyframe_type_items[] = { - {-1, "ALL", ICON_ACTION, "All Types", "Include all Keyframe types"}, + {-1, "ALL", 0, "All", "Include all Keyframe types"}, {BEZT_KEYTYPE_KEYFRAME, "KEYFRAME", ICON_KEYTYPE_KEYFRAME_VEC, diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 5d266e910ad..ec1a77c9520 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -924,6 +924,23 @@ static void rna_Scene_volume_update(Main *UNUSED(bmain), Scene *UNUSED(scene), P DEG_id_tag_update(&scene->id, ID_RECALC_AUDIO_VOLUME | ID_RECALC_SEQUENCER_STRIPS); } +static const char *rna_Scene_statistics_string_get(Scene *scene, + Main *bmain, + ReportList *reports, + ViewLayer *view_layer) +{ + if (BKE_scene_find_from_view_layer(bmain, view_layer) != scene) { + BKE_reportf(reports, + RPT_ERROR, + "View Layer '%s' not found in scene '%s'", + view_layer->name, + scene->id.name + 2); + return ""; + } + + return ED_info_statistics_string(bmain, scene, view_layer); +} + static void rna_Scene_framelen_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr)) { scene->r.framelen = (float)scene->r.framapto / (float)scene->r.images; @@ -1866,11 +1883,10 @@ static void object_simplify_update(Object *ob) } if (ob->instance_collection) { - CollectionObject *cob; - - for (cob = ob->instance_collection->gobject.first; cob; cob = cob->next) { - object_simplify_update(cob->ob); + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (ob->instance_collection, ob_collection) { + object_simplify_update(ob_collection); } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } } @@ -7277,6 +7293,9 @@ void RNA_def_scene(BlenderRNA *brna) StructRNA *srna; PropertyRNA *prop; + FunctionRNA *func; + PropertyRNA *parm; + static const EnumPropertyItem audio_distance_model_items[] = { {0, "NONE", 0, "None", "No distance attenuation"}, {1, "INVERSE", 0, "Inverse", "Inverse distance model"}, @@ -7668,6 +7687,14 @@ void RNA_def_scene(BlenderRNA *brna) RNA_def_property_update(prop, NC_SCENE, NULL); RNA_def_property_update(prop, NC_SCENE, "rna_Scene_volume_update"); + /* Statistics */ + func = RNA_def_function(srna, "statistics", "rna_Scene_statistics_string_get"); + RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS); + parm = RNA_def_pointer(func, "view_layer", "ViewLayer", "View Layer", ""); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + parm = RNA_def_string(func, "statistics", NULL, 0, "Statistics", ""); + RNA_def_function_return(func, parm); + /* Grease Pencil */ prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "gpd"); diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c index fb2a60db0fd..ab84dcb0aba 100644 --- a/source/blender/makesrna/intern/rna_screen.c +++ b/source/blender/makesrna/intern/rna_screen.c @@ -288,9 +288,11 @@ static void rna_View2D_view_to_region( } } -static const char *rna_Screen_statusbar_info_get(struct bScreen *screen, Main *bmain, bContext *C) +static const char *rna_Screen_statusbar_info_get(struct bScreen *UNUSED(screen), + Main *bmain, + bContext *C) { - return ED_info_statusbar_string(bmain, screen, C); + return ED_info_statusbar_string(bmain, CTX_data_scene(C), CTX_data_view_layer(C)); } #else diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 03a70be6def..360059d8bec 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -2984,6 +2984,13 @@ static void rna_def_space_outliner(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}, }; + static const EnumPropertyItem sort_method_items[] = { + {SO_SORT_FREE, "FREE", 0, "Manual", "Sort objects and collections manually"}, + {SO_SORT_ALPHA, "ALPHA", 0, "Name", "Sort objects and collections by name alphabetically"}, + {SO_SORT_TYPE, "TYPE", 0, "Type", "Sort objects by type"}, + {0, NULL, 0, NULL, NULL}, + }; + static const EnumPropertyItem filter_state_items[] = { {SO_FILTER_OB_ALL, "ALL", 0, "All", "Show all objects in the view layer"}, {SO_FILTER_OB_VISIBLE, "VISIBLE", 0, "Visible", "Show visible objects"}, @@ -3021,9 +3028,10 @@ static void rna_def_space_outliner(BlenderRNA *brna) prop, "Complete Matches Only", "Only use complete matches of search string"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); - prop = RNA_def_property(srna, "use_sort_alpha", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SO_SKIP_SORT_ALPHA); - RNA_def_property_ui_text(prop, "Sort Alphabetically", ""); + prop = RNA_def_property(srna, "sort_method", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "sort_method"); + RNA_def_property_enum_items(prop, sort_method_items); + RNA_def_property_ui_text(prop, "Sort Type", "Outliner sort method"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); prop = RNA_def_property(srna, "use_sync_select", PROP_BOOLEAN, PROP_NONE); @@ -3032,6 +3040,12 @@ static void rna_def_space_outliner(BlenderRNA *brna) prop, "Sync Outliner Selection", "Sync outliner selection with other editors"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); + prop = RNA_def_property(srna, "show_mode_column", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", SO_MODE_COLUMN); + RNA_def_property_ui_text( + prop, "Show Mode Column", "Show the mode column for mode toggle and activation"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); + /* Granular restriction column option. */ prop = RNA_def_property(srna, "show_restrict_column_enable", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "show_restrict_flags", SO_RESTRICT_ENABLE); @@ -3092,6 +3106,11 @@ static void rna_def_space_outliner(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Show Object Children", "Show children"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); + prop = RNA_def_property(srna, "use_filter_row_children", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_ROW_CHILDREN); + RNA_def_property_ui_text(prop, "Show Row Children", "Show children on collapsed rows"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); + prop = RNA_def_property(srna, "use_filter_collection", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_COLLECTION); RNA_def_property_ui_text(prop, "Show Collections", "Show collections"); diff --git a/source/blender/python/bmesh/bmesh_py_ops_call.c b/source/blender/python/bmesh/bmesh_py_ops_call.c index a387ba31c84..d0676ec1947 100644 --- a/source/blender/python/bmesh/bmesh_py_ops_call.c +++ b/source/blender/python/bmesh/bmesh_py_ops_call.c @@ -228,7 +228,7 @@ static int bpy_slot_from_py(BMesh *bm, break; } case BMO_OP_SLOT_FLT: { - float param = PyFloat_AsDouble(value); + const float param = PyFloat_AsDouble(value); if (param == -1 && PyErr_Occurred()) { PyErr_Format(PyExc_TypeError, "%.200s: keyword \"%.200s\" expected a float, not %.200s", @@ -840,7 +840,7 @@ PyObject *BPy_BMO_call(BPy_BMeshOpFunc *self, PyObject *args, PyObject *kw) { char slot_name_strip[MAX_SLOTNAME]; const char *ch = strchr(slot->slot_name, '.'); /* can't fail! */ - int tot = ch - slot->slot_name; + const int tot = ch - slot->slot_name; BLI_assert(ch != NULL); memcpy(slot_name_strip, slot->slot_name, tot); slot_name_strip[tot] = '\0'; diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c index 04bceb17c20..2b174de7136 100644 --- a/source/blender/python/bmesh/bmesh_py_types.c +++ b/source/blender/python/bmesh/bmesh_py_types.c @@ -1093,7 +1093,7 @@ static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject bool use_deform = true; bool use_cage = false; bool use_fnorm = true; - CustomData_MeshMasks data_masks = CD_MASK_BMESH; + const CustomData_MeshMasks data_masks = CD_MASK_BMESH; BPY_BM_CHECK_OBJ(self); @@ -1346,7 +1346,7 @@ static PyObject *bpy_bmesh_transform(BPy_BMElem *self, PyObject *args, PyObject } } else { - char filter_flags_ch = (char)filter_flags; + const char filter_flags_ch = (char)filter_flags; BM_ITER_MESH (eve, &iter, self->bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(eve, filter_flags_ch)) { mul_m4_v3((float(*)[4])mat_ptr, eve->co); @@ -3222,7 +3222,7 @@ static PyObject *bpy_bmelemseq_subscript(BPy_BMElemSeq *self, PyObject *key) { /* don't need error check here */ if (PyIndex_Check(key)) { - Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError); + const Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError); if (i == -1 && PyErr_Occurred()) { return NULL; } @@ -3255,7 +3255,7 @@ static PyObject *bpy_bmelemseq_subscript(BPy_BMElemSeq *self, PyObject *key) if (start < 0 || stop < 0) { /* only get the length for negative values */ - Py_ssize_t len = bpy_bmelemseq_length(self); + const Py_ssize_t len = bpy_bmelemseq_length(self); if (start < 0) { start += len; } diff --git a/source/blender/python/bmesh/bmesh_py_types_customdata.c b/source/blender/python/bmesh/bmesh_py_types_customdata.c index 51616030d30..a9a9a3ad5d9 100644 --- a/source/blender/python/bmesh/bmesh_py_types_customdata.c +++ b/source/blender/python/bmesh/bmesh_py_types_customdata.c @@ -714,7 +714,7 @@ static PyObject *bpy_bmlayercollection_subscript_slice(BPy_BMLayerCollection *se Py_ssize_t start, Py_ssize_t stop) { - Py_ssize_t len = bpy_bmlayercollection_length(self); + const Py_ssize_t len = bpy_bmlayercollection_length(self); int count = 0; PyObject *tuple; @@ -746,7 +746,7 @@ static PyObject *bpy_bmlayercollection_subscript(BPy_BMLayerCollection *self, Py return bpy_bmlayercollection_subscript_str(self, _PyUnicode_AsString(key)); } if (PyIndex_Check(key)) { - Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError); + const Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError); if (i == -1 && PyErr_Occurred()) { return NULL; } @@ -779,7 +779,7 @@ static PyObject *bpy_bmlayercollection_subscript(BPy_BMLayerCollection *self, Py if (start < 0 || stop < 0) { /* only get the length for negative values */ - Py_ssize_t len = bpy_bmlayercollection_length(self); + const Py_ssize_t len = bpy_bmlayercollection_length(self); if (start < 0) { start += len; } @@ -1127,7 +1127,7 @@ int BPy_BMLayerItem_SetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer, PyObj } case CD_PROP_FLOAT: case CD_PAINT_MASK: { - float tmp_val = PyFloat_AsDouble(py_value); + const float tmp_val = PyFloat_AsDouble(py_value); if (UNLIKELY(tmp_val == -1 && PyErr_Occurred())) { PyErr_Format( PyExc_TypeError, "expected a float, not a %.200s", Py_TYPE(py_value)->tp_name); @@ -1140,7 +1140,7 @@ int BPy_BMLayerItem_SetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer, PyObj } case CD_PROP_INT32: case CD_FACEMAP: { - int tmp_val = PyC_Long_AsI32(py_value); + const int tmp_val = PyC_Long_AsI32(py_value); if (UNLIKELY(tmp_val == -1 && PyErr_Occurred())) { /* error is set */ ret = -1; @@ -1187,7 +1187,7 @@ int BPy_BMLayerItem_SetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer, PyObj break; } case CD_BWEIGHT: { - float tmp_val = PyFloat_AsDouble(py_value); + const float tmp_val = PyFloat_AsDouble(py_value); if (UNLIKELY(tmp_val == -1 && PyErr_Occurred())) { PyErr_Format( PyExc_TypeError, "expected a float, not a %.200s", Py_TYPE(py_value)->tp_name); @@ -1199,7 +1199,7 @@ int BPy_BMLayerItem_SetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer, PyObj break; } case CD_CREASE: { - float tmp_val = PyFloat_AsDouble(py_value); + const float tmp_val = PyFloat_AsDouble(py_value); if (UNLIKELY(tmp_val == -1 && PyErr_Occurred())) { PyErr_Format( PyExc_TypeError, "expected a float, not a %.200s", Py_TYPE(py_value)->tp_name); diff --git a/source/blender/python/bmesh/bmesh_py_types_select.c b/source/blender/python/bmesh/bmesh_py_types_select.c index d69668341ff..9bb9815f731 100644 --- a/source/blender/python/bmesh/bmesh_py_types_select.c +++ b/source/blender/python/bmesh/bmesh_py_types_select.c @@ -246,7 +246,7 @@ static PyObject *bpy_bmeditselseq_subscript(BPy_BMEditSelSeq *self, PyObject *ke { /* don't need error check here */ if (PyIndex_Check(key)) { - Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError); + const Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError); if (i == -1 && PyErr_Occurred()) { return NULL; } @@ -279,7 +279,7 @@ static PyObject *bpy_bmeditselseq_subscript(BPy_BMEditSelSeq *self, PyObject *ke if (start < 0 || stop < 0) { /* only get the length for negative values */ - Py_ssize_t len = bpy_bmeditselseq_length(self); + const Py_ssize_t len = bpy_bmeditselseq_length(self); if (start < 0) { start += len; } diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c index 405541554c9..89fe9f8c6aa 100644 --- a/source/blender/python/generic/bgl.c +++ b/source/blender/python/generic/bgl.c @@ -461,7 +461,7 @@ int BGL_typeSize(int type) static int gl_buffer_type_from_py_buffer(Py_buffer *pybuffer) { const char format = PyC_StructFmt_type_from_str(pybuffer->format); - Py_ssize_t itemsize = pybuffer->itemsize; + const Py_ssize_t itemsize = pybuffer->itemsize; if (PyC_StructFmt_type_is_float_any(format)) { if (itemsize == 4) { @@ -705,7 +705,7 @@ static int BGL_BufferOrOffsetConverter(PyObject *object, BufferOrOffset *buffer) return 1; } if (PyNumber_Check(object)) { - Py_ssize_t offset = PyNumber_AsSsize_t(object, PyExc_IndexError); + const Py_ssize_t offset = PyNumber_AsSsize_t(object, PyExc_IndexError); if (offset == -1 && PyErr_Occurred()) { return 0; } @@ -907,7 +907,7 @@ static int Buffer_ass_item(Buffer *self, int i, PyObject *v) Buffer *row = (Buffer *)Buffer_item(self, i); if (row) { - int ret = Buffer_ass_slice(row, 0, self->dimensions[1], v); + const int ret = Buffer_ass_slice(row, 0, self->dimensions[1], v); Py_DECREF(row); return ret; } diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c index 615ce514a3e..314a34e3dec 100644 --- a/source/blender/python/generic/idprop_py_api.c +++ b/source/blender/python/generic/idprop_py_api.c @@ -435,7 +435,7 @@ static IDProperty *idp_from_PyBytes(const char *name, PyObject *ob) static int idp_array_type_from_formatstr_and_size(const char *typestr, Py_ssize_t itemsize) { - char format = PyC_StructFmt_type_from_str(typestr); + const char format = PyC_StructFmt_type_from_str(typestr); if (PyC_StructFmt_type_is_float_any(format)) { if (itemsize == 4) { @@ -473,7 +473,7 @@ static IDProperty *idp_from_PySequence_Buffer(const char *name, Py_buffer *buffe IDProperty *prop; IDPropertyTemplate val = {0}; - int id_type = idp_array_type_from_formatstr_and_size(buffer->format, buffer->itemsize); + const int id_type = idp_array_type_from_formatstr_and_size(buffer->format, buffer->itemsize); if (id_type == -1) { /* should never happen as the type has been checked before */ return NULL; @@ -560,7 +560,7 @@ static IDProperty *idp_from_PySequence(const char *name, PyObject *ob) if (PyObject_CheckBuffer(ob)) { PyObject_GetBuffer(ob, &buffer, PyBUF_SIMPLE | PyBUF_FORMAT); - char format = PyC_StructFmt_type_from_str(buffer.format); + const char format = PyC_StructFmt_type_from_str(buffer.format); if (PyC_StructFmt_type_is_float_any(format) || (PyC_StructFmt_type_is_int_any(format) && buffer.itemsize == 4)) { use_buffer = true; @@ -589,7 +589,7 @@ static IDProperty *idp_from_PySequence(const char *name, PyObject *ob) static IDProperty *idp_from_PyMapping(const char *name, PyObject *ob) { IDProperty *prop; - IDPropertyTemplate val = {0}; + const IDPropertyTemplate val = {0}; PyObject *keys, *vals, *key, *pval; int i, len; @@ -1559,8 +1559,8 @@ static int itemsize_by_idarray_type(int array_type) static int BPy_IDArray_getbuffer(BPy_IDArray *self, Py_buffer *view, int flags) { IDProperty *prop = self->prop; - int itemsize = itemsize_by_idarray_type(prop->subtype); - int length = itemsize * prop->len; + const int itemsize = itemsize_by_idarray_type(prop->subtype); + const int length = itemsize * prop->len; if (PyBuffer_FillInfo(view, (PyObject *)self, IDP_Array(prop), length, false, flags) == -1) { return -1; diff --git a/source/blender/python/generic/imbuf_py_api.c b/source/blender/python/generic/imbuf_py_api.c index 3536236754e..5dc4aa6ce7c 100644 --- a/source/blender/python/generic/imbuf_py_api.c +++ b/source/blender/python/generic/imbuf_py_api.c @@ -260,7 +260,7 @@ static int py_imbuf_filepath_set(Py_ImBuf *self, PyObject *value, void *UNUSED(c } ImBuf *ibuf = self->ibuf; - Py_ssize_t value_str_len_max = sizeof(ibuf->name); + const Py_ssize_t value_str_len_max = sizeof(ibuf->name); Py_ssize_t value_str_len; const char *value_str = _PyUnicode_AsStringAndSize(value, &value_str_len); if (value_str_len >= value_str_len_max) { @@ -425,8 +425,8 @@ static PyObject *M_imbuf_new(PyObject *UNUSED(self), PyObject *args, PyObject *k } /* TODO, make options */ - uchar planes = 4; - uint flags = IB_rect; + const uchar planes = 4; + const uint flags = IB_rect; ImBuf *ibuf = IMB_allocImBuf(UNPACK2(size), planes, flags); if (ibuf == NULL) { @@ -500,7 +500,7 @@ static PyObject *M_imbuf_write(PyObject *UNUSED(self), PyObject *args, PyObject filepath = py_imb->ibuf->name; } - bool ok = IMB_saveiff(py_imb->ibuf, filepath, IB_rect); + const bool ok = IMB_saveiff(py_imb->ibuf, filepath, IB_rect); if (ok == false) { PyErr_Format( PyExc_IOError, "write: Unable to write image file (%s) '%s'", strerror(errno), filepath); diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c index 838a1239210..195442d34f6 100644 --- a/source/blender/python/generic/py_capi_utils.c +++ b/source/blender/python/generic/py_capi_utils.c @@ -207,7 +207,7 @@ PyObject *PyC_Tuple_PackArray_Bool(const bool *array, uint len) */ void PyC_Tuple_Fill(PyObject *tuple, PyObject *value) { - uint tot = PyTuple_GET_SIZE(tuple); + const uint tot = PyTuple_GET_SIZE(tuple); uint i; for (i = 0; i < tot; i++) { @@ -218,7 +218,7 @@ void PyC_Tuple_Fill(PyObject *tuple, PyObject *value) void PyC_List_Fill(PyObject *list, PyObject *value) { - uint tot = PyList_GET_SIZE(list); + const uint tot = PyList_GET_SIZE(list); uint i; for (i = 0; i < tot; i++) { @@ -377,7 +377,7 @@ void PyC_StackSpit(void) } /* lame but handy */ - PyGILState_STATE gilstate = PyGILState_Ensure(); + const PyGILState_STATE gilstate = PyGILState_Ensure(); PyRun_SimpleString("__import__('traceback').print_stack()"); PyGILState_Release(gilstate); } @@ -948,7 +948,7 @@ void PyC_RunQuicky(const char *filepath, int n, ...) FILE *fp = fopen(filepath, "r"); if (fp) { - PyGILState_STATE gilstate = PyGILState_Ensure(); + const PyGILState_STATE gilstate = PyGILState_Ensure(); va_list vargs; @@ -1423,7 +1423,7 @@ bool PyC_RunString_AsString(const char *imports[], */ int PyC_Long_AsBool(PyObject *value) { - int test = _PyLong_AsInt(value); + const int test = _PyLong_AsInt(value); if (UNLIKELY((uint)test > 1)) { PyErr_SetString(PyExc_TypeError, "Python number not a bool (0/1)"); return -1; @@ -1433,7 +1433,7 @@ int PyC_Long_AsBool(PyObject *value) int8_t PyC_Long_AsI8(PyObject *value) { - int test = _PyLong_AsInt(value); + const int test = _PyLong_AsInt(value); if (UNLIKELY(test < INT8_MIN || test > INT8_MAX)) { PyErr_SetString(PyExc_OverflowError, "Python int too large to convert to C int8"); return -1; @@ -1443,7 +1443,7 @@ int8_t PyC_Long_AsI8(PyObject *value) int16_t PyC_Long_AsI16(PyObject *value) { - int test = _PyLong_AsInt(value); + const int test = _PyLong_AsInt(value); if (UNLIKELY(test < INT16_MIN || test > INT16_MAX)) { PyErr_SetString(PyExc_OverflowError, "Python int too large to convert to C int16"); return -1; @@ -1458,7 +1458,7 @@ int16_t PyC_Long_AsI16(PyObject *value) uint8_t PyC_Long_AsU8(PyObject *value) { - ulong test = PyLong_AsUnsignedLong(value); + const ulong test = PyLong_AsUnsignedLong(value); if (UNLIKELY(test > UINT8_MAX)) { PyErr_SetString(PyExc_OverflowError, "Python int too large to convert to C uint8"); return (uint8_t)-1; @@ -1468,7 +1468,7 @@ uint8_t PyC_Long_AsU8(PyObject *value) uint16_t PyC_Long_AsU16(PyObject *value) { - ulong test = PyLong_AsUnsignedLong(value); + const ulong test = PyLong_AsUnsignedLong(value); if (UNLIKELY(test > UINT16_MAX)) { PyErr_SetString(PyExc_OverflowError, "Python int too large to convert to C uint16"); return (uint16_t)-1; @@ -1478,7 +1478,7 @@ uint16_t PyC_Long_AsU16(PyObject *value) uint32_t PyC_Long_AsU32(PyObject *value) { - ulong test = PyLong_AsUnsignedLong(value); + const ulong test = PyLong_AsUnsignedLong(value); if (UNLIKELY(test > UINT32_MAX)) { PyErr_SetString(PyExc_OverflowError, "Python int too large to convert to C uint32"); return (uint32_t)-1; diff --git a/source/blender/python/gpu/gpu_py_shader.c b/source/blender/python/gpu/gpu_py_shader.c index c1a6ce09d37..f9ff0558570 100644 --- a/source/blender/python/gpu/gpu_py_shader.c +++ b/source/blender/python/gpu/gpu_py_shader.c @@ -78,7 +78,7 @@ static int bpygpu_uniform_location_get(GPUShader *shader, const char *name, const char *error_prefix) { - int uniform = GPU_shader_get_uniform(shader, name); + const int uniform = GPU_shader_get_uniform(shader, name); if (uniform == -1) { PyErr_Format(PyExc_ValueError, "%s: uniform %.32s not found", error_prefix, name); @@ -158,7 +158,7 @@ static PyObject *bpygpu_shader_uniform_from_name(BPyGPUShader *self, PyObject *a return NULL; } - int uniform = bpygpu_uniform_location_get(self->shader, name, "GPUShader.get_uniform"); + const int uniform = bpygpu_uniform_location_get(self->shader, name, "GPUShader.get_uniform"); if (uniform == -1) { return NULL; @@ -184,7 +184,7 @@ static PyObject *bpygpu_shader_uniform_block_from_name(BPyGPUShader *self, PyObj return NULL; } - int uniform = GPU_shader_get_uniform_block(self->shader, name); + const int uniform = GPU_shader_get_uniform_block(self->shader, name); if (uniform == -1) { PyErr_Format(PyExc_ValueError, "GPUShader.get_uniform_block: uniform %.32s not found", name); @@ -504,7 +504,7 @@ static PyObject *bpygpu_shader_attr_from_name(BPyGPUShader *self, PyObject *arg) return NULL; } - int attr = GPU_shader_get_attribute(self->shader, name); + const int attr = GPU_shader_get_attribute(self->shader, name); if (attr == -1) { PyErr_Format(PyExc_ValueError, "GPUShader.attr_from_name: attribute %.32s not found", name); diff --git a/source/blender/python/gpu/gpu_py_vertex_buffer.c b/source/blender/python/gpu/gpu_py_vertex_buffer.c index 57290fdc3c4..9372770e45e 100644 --- a/source/blender/python/gpu/gpu_py_vertex_buffer.c +++ b/source/blender/python/gpu/gpu_py_vertex_buffer.c @@ -134,7 +134,7 @@ static bool bpygpu_vertbuf_fill_impl(GPUVertBuf *vbo, return false; } - uint comp_len = pybuffer.ndim == 1 ? 1 : (uint)pybuffer.shape[1]; + const uint comp_len = pybuffer.ndim == 1 ? 1 : (uint)pybuffer.shape[1]; if (pybuffer.shape[0] != vbo->vertex_len) { PyErr_Format( diff --git a/source/blender/python/gpu/gpu_py_vertex_format.c b/source/blender/python/gpu/gpu_py_vertex_format.c index d8266be7e2c..1cbcaba6bfb 100644 --- a/source/blender/python/gpu/gpu_py_vertex_format.c +++ b/source/blender/python/gpu/gpu_py_vertex_format.c @@ -112,7 +112,7 @@ static int bpygpu_ParseVertCompType(PyObject *o, void *p) return 0; } - int comp_type = bpygpu_parse_component_type(str, length); + const int comp_type = bpygpu_parse_component_type(str, length); if (comp_type == -1) { PyErr_Format(PyExc_ValueError, "unknown component type: '%s", str); return 0; @@ -132,7 +132,7 @@ static int bpygpu_ParseVertFetchMode(PyObject *o, void *p) return 0; } - int fetch_mode = bpygpu_parse_fetch_mode(str, length); + const int fetch_mode = bpygpu_parse_fetch_mode(str, length); if (fetch_mode == -1) { PyErr_Format(PyExc_ValueError, "unknown type literal: '%s'", str); return 0; diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c index 4ee936aff91..f0de05f95b3 100644 --- a/source/blender/python/intern/bpy_app.c +++ b/source/blender/python/intern/bpy_app.c @@ -343,7 +343,7 @@ static PyObject *bpy_app_debug_value_get(PyObject *UNUSED(self), void *UNUSED(cl static int bpy_app_debug_value_set(PyObject *UNUSED(self), PyObject *value, void *UNUSED(closure)) { - short param = PyC_Long_AsI16(value); + const short param = PyC_Long_AsI16(value); if (param == -1 && PyErr_Occurred()) { PyC_Err_SetString_Prefix(PyExc_TypeError, diff --git a/source/blender/python/intern/bpy_app_handlers.c b/source/blender/python/intern/bpy_app_handlers.c index cdbd3bc0b9c..a874e23ff32 100644 --- a/source/blender/python/intern/bpy_app_handlers.c +++ b/source/blender/python/intern/bpy_app_handlers.c @@ -318,7 +318,7 @@ void bpy_app_generic_callback(struct Main *UNUSED(main), { PyObject *cb_list = py_cb_array[POINTER_AS_INT(arg)]; if (PyList_GET_SIZE(cb_list) > 0) { - PyGILState_STATE gilstate = PyGILState_Ensure(); + const PyGILState_STATE gilstate = PyGILState_Ensure(); const int num_arguments = 2; PyObject *args_all = PyTuple_New(num_arguments); /* save python creating each call */ diff --git a/source/blender/python/intern/bpy_app_icons.c b/source/blender/python/intern/bpy_app_icons.c index 2e688609961..7cca3ae4700 100644 --- a/source/blender/python/intern/bpy_app_icons.c +++ b/source/blender/python/intern/bpy_app_icons.c @@ -71,8 +71,8 @@ static PyObject *bpy_app_icons_new_triangles(PyObject *UNUSED(self), PyObject *a return NULL; } - int coords_size = sizeof(uchar[2]) * tris_len * 3; - int colors_size = sizeof(uchar[4]) * tris_len * 3; + const int coords_size = sizeof(uchar[2]) * tris_len * 3; + const int colors_size = sizeof(uchar[4]) * tris_len * 3; uchar(*coords)[2] = MEM_mallocN(coords_size, __func__); uchar(*colors)[4] = MEM_mallocN(colors_size, __func__); @@ -86,7 +86,7 @@ static PyObject *bpy_app_icons_new_triangles(PyObject *UNUSED(self), PyObject *a geom->coords = coords; geom->colors = colors; geom->icon_id = 0; - int icon_id = BKE_icon_geom_ensure(geom); + const int icon_id = BKE_icon_geom_ensure(geom); return PyLong_FromLong(icon_id); } @@ -117,7 +117,7 @@ static PyObject *bpy_app_icons_new_triangles_from_file(PyObject *UNUSED(self), PyErr_SetString(PyExc_ValueError, "Unable to load from file"); return NULL; } - int icon_id = BKE_icon_geom_ensure(geom); + const int icon_id = BKE_icon_geom_ensure(geom); return PyLong_FromLong(icon_id); } diff --git a/source/blender/python/intern/bpy_app_opensubdiv.c b/source/blender/python/intern/bpy_app_opensubdiv.c index 3f14c4dca57..09cd6201831 100644 --- a/source/blender/python/intern/bpy_app_opensubdiv.c +++ b/source/blender/python/intern/bpy_app_opensubdiv.c @@ -63,7 +63,7 @@ static PyObject *make_opensubdiv_info(void) #define SetObjItem(obj) PyStructSequence_SET_ITEM(opensubdiv_info, pos++, obj) #ifdef WITH_OPENSUBDIV - int curversion = openSubdiv_getVersionHex(); + const int curversion = openSubdiv_getVersionHex(); SetObjItem(PyBool_FromLong(1)); SetObjItem(PyC_Tuple_Pack_I32(curversion / 10000, (curversion / 100) % 100, curversion % 100)); SetObjItem(PyUnicode_FromFormat( diff --git a/source/blender/python/intern/bpy_app_timers.c b/source/blender/python/intern/bpy_app_timers.c index f1dd8b9e803..af299952b72 100644 --- a/source/blender/python/intern/bpy_app_timers.c +++ b/source/blender/python/intern/bpy_app_timers.c @@ -65,7 +65,7 @@ static double py_timer_execute(uintptr_t UNUSED(uuid), void *user_data) gilstate = PyGILState_Ensure(); PyObject *py_ret = PyObject_CallObject(function, NULL); - double ret = handle_returned_value(function, py_ret); + const double ret = handle_returned_value(function, py_ret); PyGILState_Release(gilstate); @@ -151,7 +151,7 @@ PyDoc_STRVAR(bpy_app_timers_is_registered_doc, " :rtype: bool\n"); static PyObject *bpy_app_timers_is_registered(PyObject *UNUSED(self), PyObject *function) { - bool ret = BLI_timer_is_registered((intptr_t)function); + const bool ret = BLI_timer_is_registered((intptr_t)function); return PyBool_FromLong(ret); } diff --git a/source/blender/python/intern/bpy_app_translations.c b/source/blender/python/intern/bpy_app_translations.c index c152c920453..f95261df6b2 100644 --- a/source/blender/python/intern/bpy_app_translations.c +++ b/source/blender/python/intern/bpy_app_translations.c @@ -92,7 +92,7 @@ static GHashKey *_ghashutil_keyalloc(const void *msgctxt, const void *msgid) static uint _ghashutil_keyhash(const void *ptr) { const GHashKey *key = ptr; - uint hash = BLI_ghashutil_strhash(key->msgctxt); + const uint hash = BLI_ghashutil_strhash(key->msgctxt); return hash ^ BLI_ghashutil_strhash(key->msgid); } diff --git a/source/blender/python/intern/bpy_driver.c b/source/blender/python/intern/bpy_driver.c index 7fb4b0c469c..4ef685b7987 100644 --- a/source/blender/python/intern/bpy_driver.c +++ b/source/blender/python/intern/bpy_driver.c @@ -228,7 +228,7 @@ static void bpy_pydriver_namespace_clear_self(void) void BPY_driver_reset(void) { PyGILState_STATE gilstate; - bool use_gil = true; /* !PyC_IsInterpreterActive(); */ + const bool use_gil = true; /* !PyC_IsInterpreterActive(); */ if (use_gil) { gilstate = PyGILState_Ensure(); @@ -594,7 +594,7 @@ float BPY_driver_exec(struct PathResolvedRNA *anim_rna, #endif { /* try to get variable value */ - float tval = driver_get_variable_value(driver, dvar); + const float tval = driver_get_variable_value(driver, dvar); driver_arg = PyFloat_FromDouble((double)tval); } diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index b0b36baa839..bc7318e1a15 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -169,7 +169,7 @@ void BPY_text_free_code(Text *text) { if (text->compiled) { PyGILState_STATE gilstate; - bool use_gil = !PyC_IsInterpreterActive(); + const bool use_gil = !PyC_IsInterpreterActive(); if (use_gil) { gilstate = PyGILState_Ensure(); @@ -446,14 +446,14 @@ void BPY_python_backtrace(FILE *fp) void BPY_DECREF(void *pyob_ptr) { - PyGILState_STATE gilstate = PyGILState_Ensure(); + const PyGILState_STATE gilstate = PyGILState_Ensure(); Py_DECREF((PyObject *)pyob_ptr); PyGILState_Release(gilstate); } void BPY_DECREF_RNA_INVALIDATE(void *pyob_ptr) { - PyGILState_STATE gilstate = PyGILState_Ensure(); + const PyGILState_STATE gilstate = PyGILState_Ensure(); const int do_invalidate = (Py_REFCNT((PyObject *)pyob_ptr) > 1); Py_DECREF((PyObject *)pyob_ptr); if (do_invalidate) { @@ -509,7 +509,7 @@ void BPY_modules_load_user(bContext *C) int BPY_context_member_get(bContext *C, const char *member, bContextDataResult *result) { PyGILState_STATE gilstate; - bool use_gil = !PyC_IsInterpreterActive(); + const bool use_gil = !PyC_IsInterpreterActive(); PyObject *pyctx; PyObject *item; @@ -544,7 +544,7 @@ int BPY_context_member_get(bContext *C, const char *member, bContextDataResult * PyErr_Clear(); } else { - int len = PySequence_Fast_GET_SIZE(seq_fast); + const int len = PySequence_Fast_GET_SIZE(seq_fast); PyObject **seq_fast_items = PySequence_Fast_ITEMS(seq_fast); int i; diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c index bcf13b1d88f..bdad4d03ae7 100644 --- a/source/blender/python/intern/bpy_library_load.c +++ b/source/blender/python/intern/bpy_library_load.c @@ -321,7 +321,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) { Main *bmain = CTX_data_main(BPy_GetContext()); Main *mainl = NULL; - int err = 0; + const int err = 0; const bool do_append = ((self->flag & FILE_LINK) == 0); BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true); @@ -338,7 +338,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) // printf("lib: %s\n", name_plural); if (ls && PyList_Check(ls)) { /* loop */ - Py_ssize_t size = PyList_GET_SIZE(ls); + const Py_ssize_t size = PyList_GET_SIZE(ls); Py_ssize_t i; for (i = 0; i < size; i++) { @@ -423,7 +423,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) const char *name_plural = BKE_idtype_idcode_to_name_plural(idcode); PyObject *ls = PyDict_GetItemString(self->dict, name_plural); if (ls && PyList_Check(ls)) { - Py_ssize_t size = PyList_GET_SIZE(ls); + const Py_ssize_t size = PyList_GET_SIZE(ls); Py_ssize_t i; PyObject *item; diff --git a/source/blender/python/intern/bpy_msgbus.c b/source/blender/python/intern/bpy_msgbus.c index 45c5aba1e3e..3739f56dc79 100644 --- a/source/blender/python/intern/bpy_msgbus.c +++ b/source/blender/python/intern/bpy_msgbus.c @@ -192,7 +192,7 @@ static void bpy_msgbus_notify(bContext *C, static void bpy_msgbus_subscribe_value_free_data(struct wmMsgSubscribeKey *UNUSED(msg_key), struct wmMsgSubscribeValue *msg_val) { - PyGILState_STATE gilstate = PyGILState_Ensure(); + const PyGILState_STATE gilstate = PyGILState_Ensure(); Py_DECREF(msg_val->owner); Py_DECREF(msg_val->user_data); PyGILState_Release(gilstate); diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c index 66c67ca061c..859f0027f14 100644 --- a/source/blender/python/intern/bpy_props.c +++ b/source/blender/python/intern/bpy_props.c @@ -351,7 +351,7 @@ static bool bpy_prop_boolean_get_cb(struct PointerRNA *ptr, struct PropertyRNA * value = false; } else { - int value_i = PyC_Long_AsBool(ret); + const int value_i = PyC_Long_AsBool(ret); if (value_i == -1 && PyErr_Occurred()) { PyC_Err_PrintWithFunc(py_func); @@ -443,7 +443,7 @@ static bool bpy_prop_poll_cb(struct PointerRNA *self, PyObject *ret; bool result; const int is_write_ok = pyrna_write_check(); - PyGILState_STATE gilstate = PyGILState_Ensure(); + const PyGILState_STATE gilstate = PyGILState_Ensure(); BLI_assert(self != NULL); @@ -560,7 +560,7 @@ static void bpy_prop_boolean_array_set_cb(struct PointerRNA *ptr, PyGILState_STATE gilstate; bool use_gil; const bool is_write_ok = pyrna_write_check(); - int len = RNA_property_array_length(ptr, prop); + const int len = RNA_property_array_length(ptr, prop); BLI_assert(py_data != NULL); @@ -804,7 +804,7 @@ static void bpy_prop_int_array_set_cb(struct PointerRNA *ptr, PyGILState_STATE gilstate; bool use_gil; const bool is_write_ok = pyrna_write_check(); - int len = RNA_property_array_length(ptr, prop); + const int len = RNA_property_array_length(ptr, prop); BLI_assert(py_data != NULL); @@ -1048,7 +1048,7 @@ static void bpy_prop_float_array_set_cb(struct PointerRNA *ptr, PyGILState_STATE gilstate; bool use_gil; const bool is_write_ok = pyrna_write_check(); - int len = RNA_property_array_length(ptr, prop); + const int len = RNA_property_array_length(ptr, prop); BLI_assert(py_data != NULL); diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 955a24bc880..a3ded8813ac 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -464,7 +464,7 @@ static int mathutils_rna_vector_set(BaseMathObject *bmo, int subtype) if (subtype == MATHUTILS_CB_SUBTYPE_EUL) { EulerObject *eul = (EulerObject *)bmo; PropertyRNA *prop_eul_order = NULL; - short order = pyrna_rotation_euler_order_get(&self->ptr, eul->order, &prop_eul_order); + const short order = pyrna_rotation_euler_order_get(&self->ptr, eul->order, &prop_eul_order); if (order != eul->order) { RNA_property_enum_set(&self->ptr, prop_eul_order, eul->order); if (RNA_property_update_check(prop_eul_order)) { @@ -599,7 +599,7 @@ static short pyrna_rotation_euler_order_get(PointerRNA *ptr, } if (*r_prop_eul_order) { - short order = RNA_property_enum_get(ptr, *r_prop_eul_order); + const short order = RNA_property_enum_get(ptr, *r_prop_eul_order); /* Could be quat or axisangle. */ if (order >= EULER_ORDER_XYZ && order <= EULER_ORDER_ZYX) { return order; @@ -714,7 +714,8 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop) /* Attempt to get order, * only needed for thick types since wrapped with update via callbacks. */ PropertyRNA *prop_eul_order = NULL; - short order = pyrna_rotation_euler_order_get(ptr, EULER_ORDER_XYZ, &prop_eul_order); + const short order = pyrna_rotation_euler_order_get( + ptr, EULER_ORDER_XYZ, &prop_eul_order); ret = Euler_CreatePyObject(NULL, order, NULL); /* TODO, get order from RNA. */ RNA_property_float_get_array(ptr, prop, ((EulerObject *)ret)->eul); @@ -1725,7 +1726,7 @@ static int pyrna_py_to_prop( } case PROP_INT: { int overflow; - long param = PyLong_AsLongAndOverflow(value, &overflow); + const long param = PyLong_AsLongAndOverflow(value, &overflow); if (overflow || (param > INT_MAX) || (param < INT_MIN)) { PyErr_Format(PyExc_ValueError, "%.200s %.200s.%.200s value not in 'int' range " @@ -1757,7 +1758,7 @@ static int pyrna_py_to_prop( break; } case PROP_FLOAT: { - float param = PyFloat_AsDouble(value); + const float param = PyFloat_AsDouble(value); if (PyErr_Occurred()) { PyErr_Format(PyExc_TypeError, "%.200s %.200s.%.200s expected a float type, not %.200s", @@ -1935,8 +1936,8 @@ static int pyrna_py_to_prop( PyObject *value_new = NULL; StructRNA *ptr_type = RNA_property_pointer_type(ptr, prop); - int flag = RNA_property_flag(prop); - int flag_parameter = RNA_parameter_flag(prop); + const int flag = RNA_property_flag(prop); + const int flag_parameter = RNA_parameter_flag(prop); /* This is really nasty! Done so we can fake the operator having direct properties, eg: * layout.prop(self, "filepath") @@ -2075,7 +2076,7 @@ static int pyrna_py_to_prop( BKE_reports_init(&reports, RPT_STORE); RNA_property_pointer_set( ptr, prop, value == Py_None ? PointerRNA_NULL : param->ptr, &reports); - int err = (BPy_reports_to_error(&reports, PyExc_RuntimeError, true)); + const int err = (BPy_reports_to_error(&reports, PyExc_RuntimeError, true)); if (err == -1) { Py_XDECREF(value_new); return -1; @@ -2233,7 +2234,7 @@ static int pyrna_py_to_prop_array_index(BPy_PropertyArrayRNA *self, int index, P /* See if we can coerce into a Python type - 'PropertyType'. */ switch (RNA_property_type(prop)) { case PROP_BOOLEAN: { - int param = PyC_Long_AsBool(value); + const int param = PyC_Long_AsBool(value); if (param == -1) { /* Error is set. */ @@ -2698,7 +2699,7 @@ static PyObject *pyrna_prop_collection_subscript(BPy_PropertyRNA *self, PyObject return pyrna_prop_collection_subscript_str(self, _PyUnicode_AsString(key)); } if (PyIndex_Check(key)) { - Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError); + const Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError); if (i == -1 && PyErr_Occurred()) { return NULL; } @@ -2732,7 +2733,7 @@ static PyObject *pyrna_prop_collection_subscript(BPy_PropertyRNA *self, PyObject if (start < 0 || stop < 0) { /* Only get the length for negative values. */ - Py_ssize_t len = (Py_ssize_t)RNA_property_collection_length(&self->ptr, self->prop); + const Py_ssize_t len = (Py_ssize_t)RNA_property_collection_length(&self->ptr, self->prop); if (start < 0) { start += len; } @@ -2827,7 +2828,7 @@ static int pyrna_prop_collection_ass_subscript(BPy_PropertyRNA *self, else #endif if (PyIndex_Check(key)) { - Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError); + const Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError); if (i == -1 && PyErr_Occurred()) { return -1; } @@ -2899,7 +2900,7 @@ static PyObject *pyrna_prop_array_subscript(BPy_PropertyArrayRNA *self, PyObject else #endif if (PyIndex_Check(key)) { - Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError); + const Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError); if (i == -1 && PyErr_Occurred()) { return NULL; } @@ -2919,11 +2920,11 @@ static PyObject *pyrna_prop_array_subscript(BPy_PropertyArrayRNA *self, PyObject if (key_slice->start == Py_None && key_slice->stop == Py_None) { /* Note: no significant advantage with optimizing [:] slice as with collections, * but include here for consistency with collection slice func */ - Py_ssize_t len = (Py_ssize_t)pyrna_prop_array_length(self); + const Py_ssize_t len = (Py_ssize_t)pyrna_prop_array_length(self); return pyrna_prop_array_subscript_slice(self, &self->ptr, self->prop, 0, len, len); } - int len = pyrna_prop_array_length(self); + const int len = pyrna_prop_array_length(self); Py_ssize_t start, stop, slicelength; if (PySlice_GetIndicesEx(key, len, &start, &stop, &step, &slicelength) < 0) { @@ -3055,7 +3056,7 @@ static int prop_subscript_ass_array_slice__bool_recursive(PyObject **value_items BLI_assert(totdim == 1); int i; for (i = 0; i != length; i++) { - int v = PyLong_AsLong(value_items[i]); + const int v = PyLong_AsLong(value_items[i]); value[i] = v; } return i; @@ -3097,7 +3098,7 @@ static int prop_subscript_ass_array_slice(PointerRNA *ptr, } int dimsize[3]; - int totdim = RNA_property_array_dimension(ptr, prop, dimsize); + const int totdim = RNA_property_array_dimension(ptr, prop, dimsize); if (totdim > 1) { BLI_assert(dimsize[arraydim] == length); } @@ -3247,7 +3248,7 @@ static int pyrna_prop_array_ass_subscript(BPy_PropertyArrayRNA *self, } else if (PyIndex_Check(key)) { - Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError); + const Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError); if (i == -1 && PyErr_Occurred()) { ret = -1; } @@ -3256,7 +3257,7 @@ static int pyrna_prop_array_ass_subscript(BPy_PropertyArrayRNA *self, } } else if (PySlice_Check(key)) { - Py_ssize_t len = pyrna_prop_array_length(self); + const Py_ssize_t len = pyrna_prop_array_length(self); Py_ssize_t start, stop, step, slicelength; if (PySlice_GetIndicesEx(key, len, &start, &stop, &step, &slicelength) < 0) { @@ -4249,7 +4250,7 @@ static PyObject *pyrna_struct_getattro(BPy_StructRNA *self, PyObject *pyname) ListBase newlb; short newtype; - int done = CTX_data_get(C, name, &newptr, &newlb, &newtype); + const int done = CTX_data_get(C, name, &newptr, &newlb, &newtype); if (done == 1) { /* Found. */ switch (newtype) { @@ -4401,7 +4402,7 @@ static int pyrna_struct_meta_idprop_setattro(PyObject *cls, PyObject *attr, PyOb if (value) { /* Check if the value is a property. */ if (is_deferred_prop) { - int ret = deferred_register_prop(srna, attr, value); + const int ret = deferred_register_prop(srna, attr, value); if (ret == -1) { /* Error set. */ return ret; @@ -4471,7 +4472,7 @@ static int pyrna_struct_setattro(BPy_StructRNA *self, PyObject *pyname, PyObject ListBase newlb; short newtype; - int done = CTX_data_get(C, name, &newptr, &newlb, &newtype); + const int done = CTX_data_get(C, name, &newptr, &newlb, &newtype); if (done == 1) { PyErr_Format( @@ -4646,7 +4647,7 @@ static PyObject *pyrna_prop_collection_idprop_add(BPy_PropertyRNA *self) static PyObject *pyrna_prop_collection_idprop_remove(BPy_PropertyRNA *self, PyObject *value) { - int key = PyLong_AsLong(value); + const int key = PyLong_AsLong(value); #ifdef USE_PEDANTIC_WRITE if (rna_disallow_writes && rna_id_write_error(&self->ptr, NULL)) { @@ -5172,7 +5173,7 @@ static int foreach_parse_args(BPy_PropertyRNA *self, static bool foreach_compat_buffer(RawPropertyType raw_type, int attr_signed, const char *format) { - char f = format ? *format : 'B'; /* B is assumed when not set */ + const char f = format ? *format : 'B'; /* B is assumed when not set */ switch (raw_type) { case PROP_RAW_CHAR: @@ -5400,7 +5401,7 @@ static PyObject *pyprop_array_foreach_getset(BPy_PropertyArrayRNA *self, PyObject *item = NULL; Py_ssize_t i, seq_size, size; void *array = NULL; - PropertyType prop_type = RNA_property_type(self->prop); + const PropertyType prop_type = RNA_property_type(self->prop); /* Get/set both take the same args currently. */ PyObject *seq; @@ -5498,7 +5499,7 @@ static PyObject *pyprop_array_foreach_getset(BPy_PropertyArrayRNA *self, } } else { - char f = buf.format ? buf.format[0] : 0; + const char f = buf.format ? buf.format[0] : 0; if ((prop_type == PROP_INT && (buf.itemsize != sizeof(int) || (f != 'l' && f != 'i'))) || (prop_type == PROP_FLOAT && (buf.itemsize != sizeof(float) || f != 'f'))) { PyBuffer_Release(&buf); @@ -8030,7 +8031,7 @@ static int rna_function_arg_count(FunctionRNA *func, int *min_count) const ListBase *lb = RNA_function_defined_parameters(func); PropertyRNA *parm; Link *link; - int flag = RNA_function_flag(func); + const int flag = RNA_function_flag(func); const bool is_staticmethod = (flag & FUNC_NO_SELF) && !(flag & FUNC_USE_SELF_TYPE); int count = is_staticmethod ? 0 : 1; bool done_min_count = false; @@ -8273,7 +8274,7 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param ParameterIterator iter; PointerRNA funcptr; int err = 0, i, ret_len = 0, arg_count; - int flag = RNA_function_flag(func); + const int flag = RNA_function_flag(func); const bool is_staticmethod = (flag & FUNC_NO_SELF) && !(flag & FUNC_USE_SELF_TYPE); const bool is_classmethod = (flag & FUNC_NO_SELF) && (flag & FUNC_USE_SELF_TYPE); @@ -9015,7 +9016,7 @@ void pyrna_struct_type_extend_capi(struct StructRNA *srna, py_method = PyCFunction_New(method, NULL); } - int err = PyDict_SetItemString(dict, method->ml_name, py_method); + const int err = PyDict_SetItemString(dict, method->ml_name, py_method); Py_DECREF(py_method); BLI_assert(!(err < 0)); UNUSED_VARS_NDEBUG(err); diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c index ae19f89c348..1d52706c5f9 100644 --- a/source/blender/python/intern/bpy_rna_anim.c +++ b/source/blender/python/intern/bpy_rna_anim.c @@ -131,7 +131,7 @@ static int pyrna_struct_anim_args_parse_ex(PointerRNA *ptr, } } else { - int array_len = RNA_property_array_length(&r_ptr, prop); + const int array_len = RNA_property_array_length(&r_ptr, prop); if ((*r_index) < -1 || (*r_index) >= array_len) { PyErr_Format(PyExc_TypeError, "%.200s index out of range \"%s\", given %d, array length is %d", @@ -316,7 +316,7 @@ PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyOb int index = -1; float cfra = FLT_MAX; const char *group_name = NULL; - char keytype = BEZT_KEYTYPE_KEYFRAME; /* XXX: Expose this as a one-off option... */ + const char keytype = BEZT_KEYTYPE_KEYFRAME; /* XXX: Expose this as a one-off option... */ int options = 0; PYRNA_STRUCT_CHECK_OBJ(self); diff --git a/source/blender/python/intern/bpy_rna_array.c b/source/blender/python/intern/bpy_rna_array.c index 66e07d556a6..cb3fe9cb600 100644 --- a/source/blender/python/intern/bpy_rna_array.c +++ b/source/blender/python/intern/bpy_rna_array.c @@ -361,7 +361,7 @@ static int validate_array(PyObject *rvalue, const char *error_prefix) { int dimsize[MAX_ARRAY_DIMENSION]; - int totdim = RNA_property_array_dimension(ptr, prop, dimsize); + const int totdim = RNA_property_array_dimension(ptr, prop, dimsize); /* validate type first because length validation may modify property array length */ @@ -466,7 +466,7 @@ static char *copy_values(PyObject *seq, const ItemConvert_FuncArg *convert_item, RNA_SetIndexFunc rna_set_index) { - int totdim = RNA_property_array_dimension(ptr, prop, NULL); + const int totdim = RNA_property_array_dimension(ptr, prop, NULL); const Py_ssize_t seq_size = PySequence_Size(seq); Py_ssize_t i; @@ -487,7 +487,7 @@ static char *copy_values(PyObject *seq, if (dim == 0) { if (MatrixObject_Check(seq)) { MatrixObject *pymat = (MatrixObject *)seq; - size_t allocsize = pymat->num_col * pymat->num_row * sizeof(float); + const size_t allocsize = pymat->num_col * pymat->num_row * sizeof(float); /* read callback already done by validate */ /* since this is the first iteration we can assume data is allocated */ @@ -993,7 +993,7 @@ PyObject *pyrna_py_from_array(PointerRNA *ptr, PropertyRNA *prop) /* TODO, multi-dimensional arrays */ int pyrna_array_contains_py(PointerRNA *ptr, PropertyRNA *prop, PyObject *value) { - int len = RNA_property_array_length(ptr, prop); + const int len = RNA_property_array_length(ptr, prop); int type; int i; @@ -1011,7 +1011,7 @@ int pyrna_array_contains_py(PointerRNA *ptr, PropertyRNA *prop, PyObject *value) switch (type) { case PROP_FLOAT: { - float value_f = PyFloat_AsDouble(value); + const float value_f = PyFloat_AsDouble(value); if (value_f == -1 && PyErr_Occurred()) { PyErr_Clear(); return 0; @@ -1044,7 +1044,7 @@ int pyrna_array_contains_py(PointerRNA *ptr, PropertyRNA *prop, PyObject *value) break; } case PROP_INT: { - int value_i = PyC_Long_AsI32(value); + const int value_i = PyC_Long_AsI32(value); if (value_i == -1 && PyErr_Occurred()) { PyErr_Clear(); return 0; @@ -1077,7 +1077,7 @@ int pyrna_array_contains_py(PointerRNA *ptr, PropertyRNA *prop, PyObject *value) break; } case PROP_BOOLEAN: { - int value_i = PyC_Long_AsBool(value); + const int value_i = PyC_Long_AsBool(value); if (value_i == -1 && PyErr_Occurred()) { PyErr_Clear(); return 0; diff --git a/source/blender/python/intern/bpy_rna_callback.c b/source/blender/python/intern/bpy_rna_callback.c index 976b8a65ac7..2f8be0c44e0 100644 --- a/source/blender/python/intern/bpy_rna_callback.c +++ b/source/blender/python/intern/bpy_rna_callback.c @@ -84,7 +84,7 @@ static void cb_region_draw(const bContext *C, ARegion *UNUSED(region), void *cus static PyObject *PyC_Tuple_CopySized(PyObject *src, int len_dst) { PyObject *dst = PyTuple_New(len_dst); - int len_src = PyTuple_GET_SIZE(src); + const int len_src = PyTuple_GET_SIZE(src); BLI_assert(len_src <= len_dst); for (int i = 0; i < len_src; i++) { PyObject *item = PyTuple_GET_ITEM(src, i); diff --git a/source/blender/python/intern/bpy_rna_driver.c b/source/blender/python/intern/bpy_rna_driver.c index 9240e34bbab..3bddd0ad8c0 100644 --- a/source/blender/python/intern/bpy_rna_driver.c +++ b/source/blender/python/intern/bpy_rna_driver.c @@ -57,7 +57,7 @@ PyObject *pyrna_driver_get_variable_value(struct ChannelDriver *driver, struct D } else { /* object & property */ - PropertyType type = RNA_property_type(prop); + const PropertyType type = RNA_property_type(prop); if (type == PROP_ENUM) { /* Note that enum's are converted to strings by default, * we want to avoid that, see: T52213 */ diff --git a/source/blender/python/intern/bpy_rna_gizmo.c b/source/blender/python/intern/bpy_rna_gizmo.c index 4ef718ef023..575824e8a86 100644 --- a/source/blender/python/intern/bpy_rna_gizmo.c +++ b/source/blender/python/intern/bpy_rna_gizmo.c @@ -63,7 +63,7 @@ static void py_rna_gizmo_handler_get_cb(const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop, void *value_p) { - PyGILState_STATE gilstate = PyGILState_Ensure(); + const PyGILState_STATE gilstate = PyGILState_Ensure(); struct BPyGizmoHandlerUserData *data = gz_prop->custom_func.user_data; PyObject *ret = PyObject_CallObject(data->fn_slots[BPY_GIZMO_FN_SLOT_GET], NULL); @@ -110,7 +110,7 @@ static void py_rna_gizmo_handler_set_cb(const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop, const void *value_p) { - PyGILState_STATE gilstate = PyGILState_Ensure(); + const PyGILState_STATE gilstate = PyGILState_Ensure(); struct BPyGizmoHandlerUserData *data = gz_prop->custom_func.user_data; @@ -159,7 +159,7 @@ static void py_rna_gizmo_handler_range_get_cb(const wmGizmo *UNUSED(gz), { struct BPyGizmoHandlerUserData *data = gz_prop->custom_func.user_data; - PyGILState_STATE gilstate = PyGILState_Ensure(); + const PyGILState_STATE gilstate = PyGILState_Ensure(); PyObject *ret = PyObject_CallObject(data->fn_slots[BPY_GIZMO_FN_SLOT_RANGE_GET], NULL); if (ret == NULL) { @@ -211,7 +211,7 @@ static void py_rna_gizmo_handler_free_cb(const wmGizmo *UNUSED(gz), wmGizmoPrope { struct BPyGizmoHandlerUserData *data = gz_prop->custom_func.user_data; - PyGILState_STATE gilstate = PyGILState_Ensure(); + const PyGILState_STATE gilstate = PyGILState_Ensure(); for (int i = 0; i < BPY_GIZMO_FN_SLOT_LEN; i++) { Py_XDECREF(data->fn_slots[i]); } @@ -234,7 +234,7 @@ PyDoc_STRVAR( " :type range: callable\n"); static PyObject *bpy_gizmo_target_set_handler(PyObject *UNUSED(self), PyObject *args, PyObject *kw) { - PyGILState_STATE gilstate = PyGILState_Ensure(); + const PyGILState_STATE gilstate = PyGILState_Ensure(); struct { PyObject *self; @@ -368,7 +368,7 @@ static PyObject *bpy_gizmo_target_get_value(PyObject *UNUSED(self), PyObject *ar return PyC_Tuple_PackArray_F32(value, array_len); } - float value = WM_gizmo_target_property_float_get(gz, gz_prop); + const float value = WM_gizmo_target_property_float_get(gz, gz_prop); return PyFloat_FromDouble(value); break; diff --git a/source/blender/python/mathutils/mathutils.c b/source/blender/python/mathutils/mathutils.c index 308d2ef9618..ca38d7008f6 100644 --- a/source/blender/python/mathutils/mathutils.c +++ b/source/blender/python/mathutils/mathutils.c @@ -208,7 +208,7 @@ int mathutils_array_parse( if (size != -1) { if (flag & MU_ARRAY_ZERO) { - int size_left = array_max - size; + const int size_left = array_max - size; if (size_left) { memset(&array[size], 0, sizeof(float) * size_left); } @@ -541,9 +541,9 @@ int EXPP_FloatsAreEqual(float af, float bf, int maxDiff) { /* solid, fast routine across all platforms * with constant time behavior */ - int ai = *(int *)(&af); - int bi = *(int *)(&bf); - int test = SIGNMASK(ai ^ bi); + const int ai = *(int *)(&af); + const int bi = *(int *)(&bf); + const int test = SIGNMASK(ai ^ bi); int diff, v1, v2; assert((0 == test) || (0xFFFFFFFF == test)); diff --git a/source/blender/python/mathutils/mathutils_Color.c b/source/blender/python/mathutils/mathutils_Color.c index 6bffff467cd..8a7f782de3c 100644 --- a/source/blender/python/mathutils/mathutils_Color.c +++ b/source/blender/python/mathutils/mathutils_Color.c @@ -749,7 +749,7 @@ PyDoc_STRVAR(Color_channel_hsv_v_doc, "HSV Value component in [0, 1].\n\n:type: static PyObject *Color_channel_hsv_get(ColorObject *self, void *type) { float hsv[3]; - int i = POINTER_AS_INT(type); + const int i = POINTER_AS_INT(type); if (BaseMath_ReadCallback(self) == -1) { return NULL; @@ -763,7 +763,7 @@ static PyObject *Color_channel_hsv_get(ColorObject *self, void *type) static int Color_channel_hsv_set(ColorObject *self, PyObject *value, void *type) { float hsv[3]; - int i = POINTER_AS_INT(type); + const int i = POINTER_AS_INT(type); float f = PyFloat_AsDouble(value); if (f == -1 && PyErr_Occurred()) { diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c index 236bb1de29d..0a524cbf24c 100644 --- a/source/blender/python/mathutils/mathutils_Matrix.c +++ b/source/blender/python/mathutils/mathutils_Matrix.c @@ -809,7 +809,7 @@ static PyObject *C_Matrix_OrthoProjection(PyObject *cls, PyObject *args) else { /* arbitrary plane */ - int vec_size = (matSize == 2 ? 2 : 3); + const int vec_size = (matSize == 2 ? 2 : 3); float tvec[4]; if (mathutils_array_parse(tvec, @@ -2156,7 +2156,8 @@ static PyObject *Matrix_str(MatrixObject *self) for (col = 0; col < self->num_col; col++) { maxsize[col] = 0; for (row = 0; row < self->num_row; row++) { - int size = BLI_snprintf(dummy_buf, sizeof(dummy_buf), "%.4f", MATRIX_ITEM(self, row, col)); + const int size = BLI_snprintf( + dummy_buf, sizeof(dummy_buf), "%.4f", MATRIX_ITEM(self, row, col)); maxsize[col] = max_ii(maxsize[col], size); } } diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c index 3ee6e766413..9bc8c0dffed 100644 --- a/source/blender/python/mathutils/mathutils_Vector.c +++ b/source/blender/python/mathutils/mathutils_Vector.c @@ -356,7 +356,7 @@ PyDoc_STRVAR(Vector_normalize_doc, " however 4D Vectors w axis is left untouched.\n"); static PyObject *Vector_normalize(VectorObject *self) { - int size = (self->size == 4 ? 3 : self->size); + const int size = (self->size == 4 ? 3 : self->size); if (BaseMath_ReadCallback_ForWrite(self) == -1) { return NULL; } @@ -2027,7 +2027,7 @@ static PyObject *Vector_richcmpr(PyObject *objectA, PyObject *objectB, int compa { VectorObject *vecA = NULL, *vecB = NULL; int result = 0; - double epsilon = 0.000001f; + const double epsilon = 0.000001f; double lenA, lenB; if (!VectorObject_Check(objectA) || !VectorObject_Check(objectB)) { diff --git a/source/blender/python/mathutils/mathutils_bvhtree.c b/source/blender/python/mathutils/mathutils_bvhtree.c index 16ea05771d0..1d477421e30 100644 --- a/source/blender/python/mathutils/mathutils_bvhtree.c +++ b/source/blender/python/mathutils/mathutils_bvhtree.c @@ -589,7 +589,7 @@ static PyObject *py_bvhtree_overlap(PyBVHTree *self, PyBVHTree *other) /* pass */ } else { - bool use_unique = (self->orig_index || other->orig_index); + const bool use_unique = (self->orig_index || other->orig_index); GSet *pair_test = use_unique ? BLI_gset_new_ex(overlap_hash, overlap_cmp, __func__, overlap_len) : NULL; @@ -1037,7 +1037,7 @@ static Mesh *bvh_get_mesh(const char *funcname, { Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); /* we only need minimum mesh data for topology and vertex locations */ - CustomData_MeshMasks data_masks = CD_MASK_BAREMESH; + const CustomData_MeshMasks data_masks = CD_MASK_BAREMESH; const bool use_render = DEG_get_mode(depsgraph) == DAG_EVAL_RENDER; *r_free_mesh = false; diff --git a/source/blender/python/mathutils/mathutils_geometry.c b/source/blender/python/mathutils/mathutils_geometry.c index 37997e9f912..e89651e0671 100644 --- a/source/blender/python/mathutils/mathutils_geometry.c +++ b/source/blender/python/mathutils/mathutils_geometry.c @@ -315,7 +315,7 @@ static PyObject *M_Geometry_intersect_tri_tri_2d(PyObject *UNUSED(self), PyObjec } } - bool ret = isect_tri_tri_v2(UNPACK3(tri_pair[0]), UNPACK3(tri_pair[1])); + const bool ret = isect_tri_tri_v2(UNPACK3(tri_pair[0]), UNPACK3(tri_pair[1])); return PyBool_FromLong(ret); } @@ -492,7 +492,7 @@ static PyObject *M_Geometry_intersect_line_plane(PyObject *UNUSED(self), PyObjec PyObject *py_line_a, *py_line_b, *py_plane_co, *py_plane_no; float line_a[3], line_b[3], plane_co[3], plane_no[3]; float isect[3]; - bool no_flip = false; + const bool no_flip = false; if (!PyArg_ParseTuple(args, "OOOO|O&:intersect_line_plane", diff --git a/source/blender/python/mathutils/mathutils_kdtree.c b/source/blender/python/mathutils/mathutils_kdtree.c index c3e66546dae..1de3c23838f 100644 --- a/source/blender/python/mathutils/mathutils_kdtree.c +++ b/source/blender/python/mathutils/mathutils_kdtree.c @@ -191,7 +191,7 @@ static int py_find_nearest_cb(void *user_data, int index, const float co[3], flo if (result) { bool use_node; - int ok = PyC_ParseBool(result, &use_node); + const int ok = PyC_ParseBool(result, &use_node); Py_DECREF(result); if (ok) { return (int)use_node; diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_types.h b/source/blender/windowmanager/gizmo/WM_gizmo_types.h index bddf54b846f..8e2b5e04e42 100644 --- a/source/blender/windowmanager/gizmo/WM_gizmo_types.h +++ b/source/blender/windowmanager/gizmo/WM_gizmo_types.h @@ -244,7 +244,7 @@ struct wmGizmo { int drag_part; /** Distance to bias this gizmo above others when picking - * (in worldspace, scaled by the gizmo scale - when used). */ + * (in world-space, scaled by the gizmo scale - when used). */ float select_bias; /** diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c index cecd324ff28..479768c3536 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c @@ -470,10 +470,10 @@ static void gizmos_draw_list(const wmGizmoMap *gzmap, const bContext *C, ListBas } else { if (is_depth) { - GPU_depth_test(true); + GPU_depth_test(GPU_DEPTH_LESS_EQUAL); } else { - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); } is_depth_prev = is_depth; } @@ -492,7 +492,7 @@ static void gizmos_draw_list(const wmGizmoMap *gzmap, const bContext *C, ListBas } if (is_depth_prev) { - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); } } @@ -534,10 +534,10 @@ static void gizmo_draw_select_3d_loop(const bContext *C, } else { if (is_depth) { - GPU_depth_test(true); + GPU_depth_test(GPU_DEPTH_LESS_EQUAL); } else { - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); } is_depth_prev = is_depth; } @@ -560,7 +560,7 @@ static void gizmo_draw_select_3d_loop(const bContext *C, } if (is_depth_prev) { - GPU_depth_test(false); + GPU_depth_test(GPU_DEPTH_NONE); } if (is_depth_skip_prev) { GPU_depth_mask(true); diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c index 67733ffc673..b245bbe054d 100644 --- a/source/blender/windowmanager/intern/wm_gesture.c +++ b/source/blender/windowmanager/intern/wm_gesture.c @@ -353,7 +353,7 @@ static void draw_filled_lasso(wmGesture *gt) draw_filled_lasso_px_cb, &lasso_fill_data); - GPU_blend(GPU_BLEND_ADDITIVE); + GPU_blend(GPU_BLEND_ADDITIVE_PREMULT); IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR); GPU_shader_bind(state.shader); @@ -361,7 +361,7 @@ static void draw_filled_lasso(wmGesture *gt) state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, red); immDrawPixelsTex( - &state, rect.xmin, rect.ymin, w, h, GL_R8, false, pixel_buf, 1.0f, 1.0f, NULL); + &state, rect.xmin, rect.ymin, w, h, GPU_R8, false, pixel_buf, 1.0f, 1.0f, NULL); GPU_shader_unbind(); |