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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/BKE_collection.h4
-rw-r--r--source/blender/blenkernel/BKE_lib_override.h9
-rw-r--r--source/blender/blenkernel/BKE_mesh_runtime.h6
-rw-r--r--source/blender/blenkernel/BKE_nla.h1
-rw-r--r--source/blender/blenkernel/BKE_object.h4
-rw-r--r--source/blender/blenkernel/BKE_scene.h2
-rw-r--r--source/blender/blenkernel/BKE_shader_fx.h1
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c6
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c16
-rw-r--r--source/blender/blenkernel/intern/collection.c54
-rw-r--r--source/blender/blenkernel/intern/collision.c26
-rw-r--r--source/blender/blenkernel/intern/gpencil.c1
-rw-r--r--source/blender/blenkernel/intern/lib_override.c427
-rw-r--r--source/blender/blenkernel/intern/mball.c58
-rw-r--r--source/blender/blenkernel/intern/nla.c31
-rw-r--r--source/blender/blenkernel/intern/object.c98
-rw-r--r--source/blender/blenkernel/intern/scene.c12
-rw-r--r--source/blender/blenkernel/intern/seqeffects.c20
-rw-r--r--source/blender/blenkernel/intern/shader_fx.c13
-rw-r--r--source/blender/blenkernel/intern/unit.c1
-rw-r--r--source/blender/blenlib/BLI_array.hh68
-rw-r--r--source/blender/blenlib/BLI_memory_utils.hh56
-rw-r--r--source/blender/blenlib/BLI_stack.hh95
-rw-r--r--source/blender/blenlib/BLI_vector.hh105
-rw-r--r--source/blender/blenlib/CMakeLists.txt2
-rw-r--r--source/blender/blenlib/intern/delaunay_2d.c3
-rw-r--r--source/blender/blenlib/intern/freetypefont.c3
-rw-r--r--source/blender/blenlib/tests/BLI_array_test.cc39
-rw-r--r--source/blender/blenlib/tests/BLI_exception_safety_test_utils.hh72
-rw-r--r--source/blender/blenlib/tests/BLI_memory_utils_test.cc2
-rw-r--r--source/blender/blenlib/tests/BLI_stack_cxx_test.cc56
-rw-r--r--source/blender/blenlib/tests/BLI_vector_test.cc84
-rw-r--r--source/blender/blenloader/intern/versioning_280.c2
-rw-r--r--source/blender/blenloader/intern/versioning_290.c83
-rw-r--r--source/blender/blenloader/intern/versioning_userdef.c10
-rw-r--r--source/blender/depsgraph/DEG_depsgraph.h8
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc4
-rw-r--r--source/blender/depsgraph/intern/depsgraph.cc6
-rw-r--r--source/blender/depsgraph/intern/depsgraph.h5
-rw-r--r--source/blender/depsgraph/intern/depsgraph_eval.cc37
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc29
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.cc4
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_flush.cc11
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_time.cc10
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_time.h4
-rw-r--r--source/blender/draw/intern/draw_cache_impl_curve.c14
-rw-r--r--source/blender/draw/intern/draw_manager.c24
-rw-r--r--source/blender/draw/intern/draw_manager_exec.c24
-rw-r--r--source/blender/draw/intern/draw_view.c2
-rw-r--r--source/blender/editors/curve/editcurve_paint.c4
-rw-r--r--source/blender/editors/gizmo_library/gizmo_draw_utils.c4
-rw-r--r--source/blender/editors/gpencil/annotate_draw.c4
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c4
-rw-r--r--source/blender/editors/include/ED_buttons.h3
-rw-r--r--source/blender/editors/include/ED_info.h9
-rw-r--r--source/blender/editors/include/ED_object.h5
-rw-r--r--source/blender/editors/include/ED_screen.h8
-rw-r--r--source/blender/editors/include/UI_interface.h10
-rw-r--r--source/blender/editors/interface/interface_panel.c388
-rw-r--r--source/blender/editors/interface/interface_templates.c8
-rw-r--r--source/blender/editors/interface/interface_widgets.c5
-rw-r--r--source/blender/editors/mask/mask_draw.c2
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c4
-rw-r--r--source/blender/editors/mesh/editmesh_preselect_edgering.c4
-rw-r--r--source/blender/editors/mesh/editmesh_preselect_elem.c4
-rw-r--r--source/blender/editors/object/object_constraint.c24
-rw-r--r--source/blender/editors/screen/area.c83
-rw-r--r--source/blender/editors/screen/screen_edit.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c12
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c10
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_cloth.c44
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mesh.c172
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_transform.c6
-rw-r--r--source/blender/editors/space_buttons/buttons_context.c42
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c4
-rw-r--r--source/blender/editors/space_image/image_draw.c2
-rw-r--r--source/blender/editors/space_image/space_image.c6
-rw-r--r--source/blender/editors/space_info/info_stats.c33
-rw-r--r--source/blender/editors/space_nla/nla_edit.c6
-rw-r--r--source/blender/editors/space_node/node_draw.c6
-rw-r--r--source/blender/editors/space_outliner/outliner_collections.c116
-rw-r--r--source/blender/editors/space_outliner/outliner_dragdrop.c586
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c365
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c55
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h12
-rw-r--r--source/blender/editors/space_outliner/outliner_ops.c1
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c528
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c535
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c282
-rw-r--r--source/blender/editors/space_outliner/space_outliner.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c2
-rw-r--r--source/blender/editors/space_userpref/space_userpref.c3
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c6
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c6
-rw-r--r--source/blender/editors/space_view3d/view3d_placement.c8
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c4
-rw-r--r--source/blender/editors/transform/transform_constraints.c14
-rw-r--r--source/blender/editors/transform/transform_gizmo_3d.c4
-rw-r--r--source/blender/editors/transform/transform_mode_edge_slide.c4
-rw-r--r--source/blender/editors/transform/transform_mode_vert_slide.c4
-rw-r--r--source/blender/editors/transform/transform_snap.c4
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c4
-rw-r--r--source/blender/functions/tests/FN_array_spans_test.cc4
-rw-r--r--source/blender/gpu/CMakeLists.txt4
-rw-r--r--source/blender/gpu/GPU_context.h1
-rw-r--r--source/blender/gpu/GPU_immediate.h3
-rw-r--r--source/blender/gpu/GPU_shader.h40
-rw-r--r--source/blender/gpu/GPU_shader_interface.h117
-rw-r--r--source/blender/gpu/GPU_state.h12
-rw-r--r--source/blender/gpu/intern/gpu_attr_binding.cc13
-rw-r--r--source/blender/gpu/intern/gpu_attr_binding_private.h6
-rw-r--r--source/blender/gpu/intern/gpu_batch_private.hh1
-rw-r--r--source/blender/gpu/intern/gpu_immediate.cc84
-rw-r--r--source/blender/gpu/intern/gpu_matrix.cc17
-rw-r--r--source/blender/gpu/intern/gpu_select_pick.c14
-rw-r--r--source/blender/gpu/intern/gpu_select_sample_query.c22
-rw-r--r--source/blender/gpu/intern/gpu_shader.cc68
-rw-r--r--source/blender/gpu/intern/gpu_shader_interface.cc532
-rw-r--r--source/blender/gpu/intern/gpu_shader_interface.hh225
-rw-r--r--source/blender/gpu/intern/gpu_shader_private.hh6
-rw-r--r--source/blender/gpu/intern/gpu_state.cc43
-rw-r--r--source/blender/gpu/intern/gpu_state_private.hh23
-rw-r--r--source/blender/gpu/opengl/gl_batch.cc48
-rw-r--r--source/blender/gpu/opengl/gl_batch.hh16
-rw-r--r--source/blender/gpu/opengl/gl_shader.cc6
-rw-r--r--source/blender/gpu/opengl/gl_shader.hh2
-rw-r--r--source/blender/gpu/opengl/gl_shader_interface.cc297
-rw-r--r--source/blender/gpu/opengl/gl_shader_interface.hh60
-rw-r--r--source/blender/gpu/opengl/gl_state.cc16
-rw-r--r--source/blender/gpu/opengl/gl_vertex_array.cc14
-rw-r--r--source/blender/gpu/opengl/gl_vertex_array.hh4
-rw-r--r--source/blender/makesdna/DNA_ID.h4
-rw-r--r--source/blender/makesdna/DNA_outliner_types.h2
-rw-r--r--source/blender/makesdna/DNA_screen_types.h7
-rw-r--r--source/blender/makesdna/DNA_space_types.h19
-rw-r--r--source/blender/makesrna/intern/makesrna.c2
-rw-r--r--source/blender/makesrna/intern/rna_brush.c2
-rw-r--r--source/blender/makesrna/intern/rna_gpencil.c2
-rw-r--r--source/blender/makesrna/intern/rna_scene.c35
-rw-r--r--source/blender/makesrna/intern/rna_screen.c6
-rw-r--r--source/blender/makesrna/intern/rna_space.c25
-rw-r--r--source/blender/python/bmesh/bmesh_py_ops_call.c4
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.c8
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_customdata.c14
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_select.c4
-rw-r--r--source/blender/python/generic/bgl.c6
-rw-r--r--source/blender/python/generic/idprop_py_api.c12
-rw-r--r--source/blender/python/generic/imbuf_py_api.c8
-rw-r--r--source/blender/python/generic/py_capi_utils.c20
-rw-r--r--source/blender/python/gpu/gpu_py_shader.c8
-rw-r--r--source/blender/python/gpu/gpu_py_vertex_buffer.c2
-rw-r--r--source/blender/python/gpu/gpu_py_vertex_format.c4
-rw-r--r--source/blender/python/intern/bpy_app.c2
-rw-r--r--source/blender/python/intern/bpy_app_handlers.c2
-rw-r--r--source/blender/python/intern/bpy_app_icons.c8
-rw-r--r--source/blender/python/intern/bpy_app_opensubdiv.c2
-rw-r--r--source/blender/python/intern/bpy_app_timers.c4
-rw-r--r--source/blender/python/intern/bpy_app_translations.c2
-rw-r--r--source/blender/python/intern/bpy_driver.c4
-rw-r--r--source/blender/python/intern/bpy_interface.c10
-rw-r--r--source/blender/python/intern/bpy_library_load.c6
-rw-r--r--source/blender/python/intern/bpy_msgbus.c2
-rw-r--r--source/blender/python/intern/bpy_props.c10
-rw-r--r--source/blender/python/intern/bpy_rna.c59
-rw-r--r--source/blender/python/intern/bpy_rna_anim.c4
-rw-r--r--source/blender/python/intern/bpy_rna_array.c14
-rw-r--r--source/blender/python/intern/bpy_rna_callback.c2
-rw-r--r--source/blender/python/intern/bpy_rna_driver.c2
-rw-r--r--source/blender/python/intern/bpy_rna_gizmo.c12
-rw-r--r--source/blender/python/mathutils/mathutils.c8
-rw-r--r--source/blender/python/mathutils/mathutils_Color.c4
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.c5
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.c4
-rw-r--r--source/blender/python/mathutils/mathutils_bvhtree.c4
-rw-r--r--source/blender/python/mathutils/mathutils_geometry.c4
-rw-r--r--source/blender/python/mathutils/mathutils_kdtree.c2
-rw-r--r--source/blender/windowmanager/gizmo/WM_gizmo_types.h2
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c12
-rw-r--r--source/blender/windowmanager/intern/wm_gesture.c4
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 &copy_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, &region->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, &region->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, &region->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, &region->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, &region->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(&region->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, &region->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,
&region->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,
&region->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, &region->type->paneltypes, NULL, -1, vertical, NULL);
+ ED_region_panels_layout_ex(C, region, &region->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, &region->type->paneltypes, contexts, contextnr, vertical, NULL);
+ ED_region_panels_layout_ex(C, region, &region->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, &region->type->paneltypes, contexts, sbuts->mainb, vertical, NULL);
+ ED_region_panels_layout_ex(C, region, &region->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, &region->type->paneltypes, contexts_base, -1, vertical, NULL);
+ ED_region_panels_layout_ex(C, region, &region->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(&region->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(
+ &region->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(&region->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
+ UI_view2d_region_to_view(
+ &region->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, &region->type->paneltypes, contexts, U.space_data.section_active, true, NULL);
+ ED_region_panels_layout_ex(C, region, &region->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();