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:
authorJulian Eisel <eiseljulian@gmail.com>2017-12-06 19:42:39 +0300
committerJulian Eisel <eiseljulian@gmail.com>2017-12-06 19:42:39 +0300
commit9d956c65a64ea6f8b1dec1a1fe11f7c67d7a0709 (patch)
treea17fa5fff8f22ea969fca67166f3842adf78f205 /source/blender
parent8f46733e77752edbd958628efd432b38dc1457f2 (diff)
parent46f518e92790a04885f4e047bb59b11019d73aa3 (diff)
Merge branch 'blender2.8' into topbar
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/alembic/intern/alembic_capi.cc4
-rw-r--r--source/blender/blenkernel/BKE_animsys.h11
-rw-r--r--source/blender/blenkernel/BKE_collection.h33
-rw-r--r--source/blender/blenkernel/BKE_context.h3
-rw-r--r--source/blender/blenkernel/BKE_group.h22
-rw-r--r--source/blender/blenkernel/BKE_layer.h29
-rw-r--r--source/blender/blenkernel/BKE_library.h2
-rw-r--r--source/blender/blenkernel/BKE_library_override.h86
-rw-r--r--source/blender/blenkernel/BKE_library_query.h3
-rw-r--r--source/blender/blenkernel/BKE_library_remap.h2
-rw-r--r--source/blender/blenkernel/BKE_object.h9
-rw-r--r--source/blender/blenkernel/BKE_screen.h7
-rw-r--r--source/blender/blenkernel/BKE_workspace.h28
-rw-r--r--source/blender/blenkernel/CMakeLists.txt2
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_legacy.c779
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c77
-rw-r--r--source/blender/blenkernel/intern/armature_update.c6
-rw-r--r--source/blender/blenkernel/intern/collection.c286
-rw-r--r--source/blender/blenkernel/intern/collision.c39
-rw-r--r--source/blender/blenkernel/intern/context.c13
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c36
-rw-r--r--source/blender/blenkernel/intern/effect.c49
-rw-r--r--source/blender/blenkernel/intern/group.c154
-rw-r--r--source/blender/blenkernel/intern/layer.c273
-rw-r--r--source/blender/blenkernel/intern/library.c83
-rw-r--r--source/blender/blenkernel/intern/library_override.c680
-rw-r--r--source/blender/blenkernel/intern/library_query.c12
-rw-r--r--source/blender/blenkernel/intern/library_remap.c14
-rw-r--r--source/blender/blenkernel/intern/lightprobe.c2
-rw-r--r--source/blender/blenkernel/intern/object.c128
-rw-r--r--source/blender/blenkernel/intern/object_dupli.c123
-rw-r--r--source/blender/blenkernel/intern/object_update.c52
-rw-r--r--source/blender/blenkernel/intern/particle.c23
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c148
-rw-r--r--source/blender/blenkernel/intern/scene.c140
-rw-r--r--source/blender/blenkernel/intern/seqeffects.c857
-rw-r--r--source/blender/blenkernel/intern/sequencer.c3
-rw-r--r--source/blender/blenkernel/intern/softbody.c76
-rw-r--r--source/blender/blenkernel/intern/texture.c4
-rw-r--r--source/blender/blenkernel/intern/tracking_stabilize.c62
-rw-r--r--source/blender/blenkernel/intern/workspace.c65
-rw-r--r--source/blender/blenlib/BLI_ghash.h74
-rw-r--r--source/blender/blenlib/BLI_sys_types.h4
-rw-r--r--source/blender/blenlib/intern/fileops.c16
-rw-r--r--source/blender/blenlib/intern/math_color_blend_inline.c40
-rw-r--r--source/blender/blenlib/intern/storage.c2
-rw-r--r--source/blender/blenloader/BLO_readfile.h18
-rw-r--r--source/blender/blenloader/intern/readfile.c287
-rw-r--r--source/blender/blenloader/intern/versioning_270.c70
-rw-r--r--source/blender/blenloader/intern/versioning_280.c146
-rw-r--r--source/blender/blenloader/intern/versioning_legacy.c2
-rw-r--r--source/blender/blenloader/intern/writefile.c360
-rw-r--r--source/blender/bmesh/intern/bmesh_marking.c8
-rw-r--r--source/blender/bmesh/operators/bmo_rotate_edges.c2
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c625
-rw-r--r--source/blender/collada/DocumentImporter.cpp2
-rw-r--r--source/blender/collada/SceneExporter.cpp12
-rw-r--r--source/blender/collada/collada_utils.cpp2
-rw-r--r--source/blender/depsgraph/CMakeLists.txt3
-rw-r--r--source/blender/depsgraph/DEG_depsgraph.h44
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_query.h40
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.cc6
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc17
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.h8
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_layer_collection.cc20
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc44
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc94
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc501
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h132
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h155
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc14
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_layer_collection.cc17
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc9
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc41
-rw-r--r--source/blender/depsgraph/intern/depsgraph.cc229
-rw-r--r--source/blender/depsgraph/intern/depsgraph.h14
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.cc1
-rw-r--r--source/blender/depsgraph/intern/depsgraph_eval.cc4
-rw-r--r--source/blender/depsgraph/intern/depsgraph_intern.h9
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query.cc165
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query_foreach.cc147
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query_iter.cc211
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc42
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc17
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_flush.cc352
-rw-r--r--source/blender/draw/CMakeLists.txt1
-rw-r--r--source/blender/draw/DRW_engine.h17
-rw-r--r--source/blender/draw/engines/basic/basic_engine.c29
-rw-r--r--source/blender/draw/engines/clay/clay_engine.c41
-rw-r--r--source/blender/draw/engines/eevee/eevee_data.c34
-rw-r--r--source/blender/draw/engines/eevee/eevee_engine.c73
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightprobes.c852
-rw-r--r--source/blender/draw/engines/eevee/eevee_lights.c140
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c3
-rw-r--r--source/blender/draw/engines/eevee/eevee_motion_blur.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h32
-rw-r--r--source/blender/draw/engines/eevee/eevee_temporal_sampling.c6
-rw-r--r--source/blender/draw/engines/eevee/eevee_volumes.c4
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl72
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl18
-rw-r--r--source/blender/draw/engines/eevee/shaders/default_frag.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl65
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_filter_visibility_frag.glsl88
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_grid_fill_frag.glsl4
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl14
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl4
-rw-r--r--source/blender/draw/engines/external/external_engine.c35
-rw-r--r--source/blender/draw/intern/DRW_render.h11
-rw-r--r--source/blender/draw/intern/draw_armature.c90
-rw-r--r--source/blender/draw/intern/draw_cache_impl_metaball.c60
-rw-r--r--source/blender/draw/intern/draw_manager.c352
-rw-r--r--source/blender/draw/modes/edit_curve_mode.c2
-rw-r--r--source/blender/draw/modes/edit_lattice_mode.c2
-rw-r--r--source/blender/draw/modes/edit_metaball_mode.c2
-rw-r--r--source/blender/draw/modes/edit_surface_mode.c2
-rw-r--r--source/blender/draw/modes/edit_text_mode.c2
-rw-r--r--source/blender/draw/modes/object_mode.c4
-rw-r--r--source/blender/draw/modes/paint_texture_mode.c2
-rw-r--r--source/blender/draw/modes/particle_mode.c2
-rw-r--r--source/blender/draw/modes/sculpt_mode.c2
-rw-r--r--source/blender/editors/armature/armature_select.c14
-rw-r--r--source/blender/editors/armature/editarmature_sketch.c2
-rw-r--r--source/blender/editors/curve/editcurve.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_convert.c2
-rw-r--r--source/blender/editors/include/ED_mesh.h1
-rw-r--r--source/blender/editors/include/ED_object.h2
-rw-r--r--source/blender/editors/include/ED_render.h11
-rw-r--r--source/blender/editors/include/ED_screen.h19
-rw-r--r--source/blender/editors/include/ED_transform_snap_object_context.h4
-rw-r--r--source/blender/editors/include/ED_view3d.h2
-rw-r--r--source/blender/editors/include/UI_interface.h5
-rw-r--r--source/blender/editors/interface/interface.c53
-rw-r--r--source/blender/editors/interface/interface_handlers.c59
-rw-r--r--source/blender/editors/interface/interface_intern.h1
-rw-r--r--source/blender/editors/interface/interface_ops.c212
-rw-r--r--source/blender/editors/interface/interface_templates.c18
-rw-r--r--source/blender/editors/interface/interface_widgets.c14
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c4
-rw-r--r--source/blender/editors/mesh/editmesh_inset.c28
-rw-r--r--source/blender/editors/mesh/editmesh_loopcut.c3
-rw-r--r--source/blender/editors/mesh/editmesh_polybuild.c8
-rw-r--r--source/blender/editors/mesh/editmesh_select.c16
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c2
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c19
-rw-r--r--source/blender/editors/object/object_add.c13
-rw-r--r--source/blender/editors/object/object_edit.c8
-rw-r--r--source/blender/editors/object/object_intern.h1
-rw-r--r--source/blender/editors/object/object_ops.c1
-rw-r--r--source/blender/editors/object/object_relations.c86
-rw-r--r--source/blender/editors/object/object_select.c3
-rw-r--r--source/blender/editors/render/render_internal.c2
-rw-r--r--source/blender/editors/render/render_update.c127
-rw-r--r--source/blender/editors/scene/scene_edit.c17
-rw-r--r--source/blender/editors/screen/area.c81
-rw-r--r--source/blender/editors/screen/screen_context.c2
-rw-r--r--source/blender/editors/screen/screen_edit.c4
-rw-r--r--source/blender/editors/screen/workspace_edit.c37
-rw-r--r--source/blender/editors/space_buttons/buttons_context.c22
-rw-r--r--source/blender/editors/space_buttons/buttons_intern.h1
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c1
-rw-r--r--source/blender/editors/space_file/file_ops.c16
-rw-r--r--source/blender/editors/space_file/space_file.c29
-rw-r--r--source/blender/editors/space_info/info_stats.c49
-rw-r--r--source/blender/editors/space_outliner/outliner_collections.c48
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c40
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c8
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h5
-rw-r--r--source/blender/editors/space_outliner/outliner_ops.c17
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c41
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c85
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c86
-rw-r--r--source/blender/editors/space_outliner/space_outliner.c3
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c31
-rw-r--r--source/blender/editors/space_time/space_time.c45
-rw-r--r--source/blender/editors/space_view3d/drawobject.c14
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c71
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c12
-rw-r--r--source/blender/editors/space_view3d/view3d_manipulator_camera.c51
-rw-r--r--source/blender/editors/space_view3d/view3d_manipulator_ruler.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c7
-rw-r--r--source/blender/editors/space_view3d/view3d_ruler.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_walk.c6
-rw-r--r--source/blender/editors/transform/transform.h2
-rw-r--r--source/blender/editors/transform/transform_conversions.c169
-rw-r--r--source/blender/editors/transform/transform_generics.c4
-rw-r--r--source/blender/editors/transform/transform_manipulator.c64
-rw-r--r--source/blender/editors/transform/transform_snap.c9
-rw-r--r--source/blender/editors/transform/transform_snap_object.c19
-rw-r--r--source/blender/editors/util/numinput.c14
-rw-r--r--source/blender/editors/util/undo.c4
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp4
-rw-r--r--source/blender/freestyle/intern/system/PythonInterpreter.h2
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c9
-rw-r--r--source/blender/gpu/intern/gpu_extensions.c3
-rw-r--r--source/blender/gpu/intern/gpu_material.c18
-rw-r--r--source/blender/makesdna/DNA_ID.h83
-rw-r--r--source/blender/makesdna/DNA_group_types.h7
-rw-r--r--source/blender/makesdna/DNA_layer_types.h8
-rw-r--r--source/blender/makesdna/DNA_lightprobe_types.h3
-rw-r--r--source/blender/makesdna/DNA_object_types.h15
-rw-r--r--source/blender/makesdna/DNA_sequence_types.h30
-rw-r--r--source/blender/makesdna/DNA_space_types.h12
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h2
-rw-r--r--source/blender/makesdna/DNA_windowmanager_types.h4
-rw-r--r--source/blender/makesdna/DNA_workspace_types.h3
-rw-r--r--source/blender/makesdna/intern/makesdna.c6
-rw-r--r--source/blender/makesrna/RNA_access.h66
-rw-r--r--source/blender/makesrna/RNA_define.h2
-rw-r--r--source/blender/makesrna/RNA_enum_types.h2
-rw-r--r--source/blender/makesrna/RNA_types.h7
-rw-r--r--source/blender/makesrna/intern/makesrna.c23
-rw-r--r--source/blender/makesrna/intern/rna_ID.c30
-rw-r--r--source/blender/makesrna/intern/rna_access.c717
-rw-r--r--source/blender/makesrna/intern/rna_animation.c32
-rw-r--r--source/blender/makesrna/intern/rna_armature.c4
-rw-r--r--source/blender/makesrna/intern/rna_context.c8
-rw-r--r--source/blender/makesrna/intern/rna_define.c31
-rw-r--r--source/blender/makesrna/intern/rna_depsgraph.c34
-rw-r--r--source/blender/makesrna/intern/rna_group.c19
-rw-r--r--source/blender/makesrna/intern/rna_image.c24
-rw-r--r--source/blender/makesrna/intern/rna_internal.h36
-rw-r--r--source/blender/makesrna/intern/rna_internal_types.h62
-rw-r--r--source/blender/makesrna/intern/rna_layer.c197
-rw-r--r--source/blender/makesrna/intern/rna_lightprobe.c19
-rw-r--r--source/blender/makesrna/intern/rna_main_api.c1
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c4
-rw-r--r--source/blender/makesrna/intern/rna_object.c11
-rw-r--r--source/blender/makesrna/intern/rna_pose.c7
-rw-r--r--source/blender/makesrna/intern/rna_rna.c1011
-rw-r--r--source/blender/makesrna/intern/rna_scene.c4
-rw-r--r--source/blender/makesrna/intern/rna_scene_api.c8
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c5
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c65
-rw-r--r--source/blender/makesrna/intern/rna_sequencer_api.c1
-rw-r--r--source/blender/makesrna/intern/rna_space.c10
-rw-r--r--source/blender/makesrna/intern/rna_ui_api.c4
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c10
-rw-r--r--source/blender/makesrna/intern/rna_wm.c61
-rw-r--r--source/blender/makesrna/intern/rna_workspace.c55
-rw-r--r--source/blender/python/gawain/gwn_py_types.c24
-rw-r--r--source/blender/python/generic/py_capi_utils.c19
-rw-r--r--source/blender/python/generic/py_capi_utils.h2
-rw-r--r--source/blender/python/intern/CMakeLists.txt16
-rw-r--r--source/blender/python/intern/bpy.c4
-rw-r--r--source/blender/python/intern/bpy_capi_utils.c (renamed from source/blender/python/intern/bpy_util.c)8
-rw-r--r--source/blender/python/intern/bpy_capi_utils.h (renamed from source/blender/python/intern/bpy_util.h)8
-rw-r--r--source/blender/python/intern/bpy_interface.c2
-rw-r--r--source/blender/python/intern/bpy_interface_atexit.c2
-rw-r--r--source/blender/python/intern/bpy_library_load.c2
-rw-r--r--source/blender/python/intern/bpy_library_write.c2
-rw-r--r--source/blender/python/intern/bpy_msgbus.c400
-rw-r--r--source/blender/python/intern/bpy_msgbus.h30
-rw-r--r--source/blender/python/intern/bpy_operator.c2
-rw-r--r--source/blender/python/intern/bpy_props.c96
-rw-r--r--source/blender/python/intern/bpy_props.h2
-rw-r--r--source/blender/python/intern/bpy_rna.c2
-rw-r--r--source/blender/python/intern/bpy_rna_anim.c2
-rw-r--r--source/blender/python/intern/bpy_rna_callback.c2
-rw-r--r--source/blender/python/intern/bpy_rna_id_collection.c2
-rw-r--r--source/blender/python/intern/bpy_rna_manipulator.c2
-rw-r--r--source/blender/python/mathutils/mathutils.h4
-rw-r--r--source/blender/python/mathutils/mathutils_Color.h3
-rw-r--r--source/blender/python/mathutils/mathutils_Euler.h3
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.h5
-rw-r--r--source/blender/python/mathutils/mathutils_Quaternion.h4
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.h4
-rw-r--r--source/blender/python/mathutils/mathutils_bvhtree.h2
-rw-r--r--source/blender/render/intern/source/convertblender.c67
-rw-r--r--source/blender/windowmanager/CMakeLists.txt5
-rw-r--r--source/blender/windowmanager/WM_message.h30
-rw-r--r--source/blender/windowmanager/WM_types.h1
-rw-r--r--source/blender/windowmanager/intern/wm.c11
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c35
-rw-r--r--source/blender/windowmanager/intern/wm_files.c5
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c20
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c6
-rw-r--r--source/blender/windowmanager/manipulators/WM_manipulator_api.h9
-rw-r--r--source/blender/windowmanager/manipulators/WM_manipulator_types.h5
-rw-r--r--source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c20
-rw-r--r--source/blender/windowmanager/manipulators/intern/wm_manipulator_target_props.c51
-rw-r--r--source/blender/windowmanager/manipulators/wm_manipulator_fn.h2
-rw-r--r--source/blender/windowmanager/message_bus/intern/wm_message_bus.c247
-rw-r--r--source/blender/windowmanager/message_bus/intern/wm_message_bus_intern.h55
-rw-r--r--source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c316
-rw-r--r--source/blender/windowmanager/message_bus/intern/wm_message_bus_static.c136
-rw-r--r--source/blender/windowmanager/message_bus/wm_message_bus.h256
289 files changed, 12380 insertions, 4696 deletions
diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc
index 7003547ead2..5e93779b5f6 100644
--- a/source/blender/alembic/intern/alembic_capi.cc
+++ b/source/blender/alembic/intern/alembic_capi.cc
@@ -845,7 +845,7 @@ static void import_endjob(void *user_data)
if (lc == NULL) {
BLI_assert(BLI_listbase_count_ex(&view_layer->layer_collections, 1) == 0);
/* when there is no collection linked to this ViewLayer, create one */
- SceneCollection *sc = BKE_collection_add(data->scene, NULL, NULL);
+ SceneCollection *sc = BKE_collection_add(&data->scene->id, NULL, COLLECTION_TYPE_NONE, NULL);
lc = BKE_collection_link(view_layer, sc);
}
@@ -853,7 +853,7 @@ static void import_endjob(void *user_data)
Object *ob = (*iter)->object();
ob->lay = data->scene->lay;
- BKE_collection_object_add(data->scene, lc->scene_collection, ob);
+ BKE_collection_object_add(&data->scene->id, lc->scene_collection, ob);
base = BKE_view_layer_base_find(view_layer, ob);
BKE_view_layer_base_select(view_layer, base);
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h
index 622767baa10..d95b4a838b8 100644
--- a/source/blender/blenkernel/BKE_animsys.h
+++ b/source/blender/blenkernel/BKE_animsys.h
@@ -35,6 +35,7 @@ struct ID;
struct ListBase;
struct Main;
struct AnimData;
+struct FCurve;
struct KeyingSet;
struct KS_Path;
struct PathResolvedRNA;
@@ -46,6 +47,7 @@ struct ReportList;
struct bAction;
struct bActionGroup;
struct AnimMapper;
+struct FCurve;
/* ************************************* */
/* AnimData API */
@@ -152,9 +154,15 @@ char *BKE_animdata_driver_path_hack(struct bContext *C, struct PointerRNA *ptr,
/* Define for callback looper used in BKE_animdata_main_cb */
typedef void (*ID_AnimData_Edit_Callback)(struct ID *id, struct AnimData *adt, void *user_data);
+/* Define for callback looper used in BKE_fcurves_main_cb */
+typedef void (*ID_FCurve_Edit_Callback)(struct ID *id, struct FCurve *fcu, void *user_data);
+
/* Loop over all datablocks applying callback */
-void BKE_animdata_main_cb(struct Main *main, ID_AnimData_Edit_Callback func, void *user_data);
+void BKE_animdata_main_cb(struct Main *bmain, ID_AnimData_Edit_Callback func, void *user_data);
+
+/* Loop over all datablocks applying callback to all its F-Curves */
+void BKE_fcurves_main_cb(struct Main *bmain, ID_FCurve_Edit_Callback func, void *user_data);
/* ************************************* */
// TODO: overrides, remapping, and path-finding api's
@@ -172,7 +180,6 @@ void BKE_animsys_evaluate_animdata(struct Scene *scene, struct ID *id, struct An
void BKE_animsys_evaluate_all_animation(struct Main *main, struct Scene *scene, float ctime);
/* TODO(sergey): This is mainly a temp public function. */
-struct FCurve;
bool BKE_animsys_execute_fcurve(struct PointerRNA *ptr, struct AnimMapper *remap, struct FCurve *fcu, float curval);
/* ------------ Specialized API --------------- */
diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h
index 52985d3ec56..48b4ff881ae 100644
--- a/source/blender/blenkernel/BKE_collection.h
+++ b/source/blender/blenkernel/BKE_collection.h
@@ -37,28 +37,35 @@ extern "C" {
struct Base;
struct BLI_Iterator;
+struct Group;
+struct ID;
+struct LayerCollection;
struct Main;
struct Object;
struct Scene;
struct SceneCollection;
-struct SceneCollection *BKE_collection_add(struct Scene *scene, struct SceneCollection *sc_parent, const char *name);
-bool BKE_collection_remove(struct Scene *scene, struct SceneCollection *sc);
-struct SceneCollection *BKE_collection_master(const struct Scene *scene);
+struct SceneCollection *BKE_collection_add(
+ struct ID *owner_id, struct SceneCollection *sc_parent, const int type, const char *name);
+bool BKE_collection_remove(struct ID *owner_id, struct SceneCollection *sc);
+void BKE_collection_copy_data(struct SceneCollection *sc_dst, struct SceneCollection *sc_src, const int flag);
+struct SceneCollection *BKE_collection_master(const struct ID *owner_id);
void BKE_collection_rename(const struct Scene *scene, struct SceneCollection *sc, const char *name);
-void BKE_collection_master_free(struct Scene *scene, const bool do_id_user);
-void BKE_collection_object_add(const struct Scene *scene, struct SceneCollection *sc, struct Object *object);
+void BKE_collection_master_free(struct ID *owner_id, const bool do_id_user);
+bool BKE_collection_object_add(const struct ID *owner_id, struct SceneCollection *sc, struct Object *object);
void BKE_collection_object_add_from(struct Scene *scene, struct Object *ob_src, struct Object *ob_dst);
-void BKE_collection_object_remove(struct Main *bmain, const struct Scene *scene, struct SceneCollection *sc, struct Object *object, const bool free_us);
-void BKE_collections_object_remove(struct Main *bmain, struct Scene *scene, struct Object *object, const bool free_us);
-void BKE_collection_object_move(const struct Scene *scene, struct SceneCollection *sc_dst, struct SceneCollection *sc_src, struct Object *ob);
+bool BKE_collection_object_remove(struct Main *bmain, struct ID *owner_id, struct SceneCollection *sc, struct Object *object, const bool free_us);
+bool BKE_collections_object_remove(struct Main *bmain, struct ID *owner_id, struct Object *object, const bool free_us);
+void BKE_collection_object_move(struct ID *owner_id, struct SceneCollection *sc_dst, struct SceneCollection *sc_src, struct Object *ob);
+
+struct Group *BKE_collection_group_create(struct Main *bmain, struct Scene *scene, struct LayerCollection *lc);
void BKE_collection_reinsert_after(const struct Scene *scene, struct SceneCollection *sc_reinsert, struct SceneCollection *sc_after);
void BKE_collection_reinsert_into(struct SceneCollection *sc_reinsert, struct SceneCollection *sc_into);
-bool BKE_collection_move_above(const struct Scene *scene, struct SceneCollection *sc_dst, struct SceneCollection *sc_src);
-bool BKE_collection_move_below(const struct Scene *scene, struct SceneCollection *sc_dst, struct SceneCollection *sc_src);
-bool BKE_collection_move_into(const struct Scene *scene, struct SceneCollection *sc_dst, struct SceneCollection *sc_src);
+bool BKE_collection_move_above(const struct ID *owner_id, struct SceneCollection *sc_dst, struct SceneCollection *sc_src);
+bool BKE_collection_move_below(const struct ID *owner_id, struct SceneCollection *sc_dst, struct SceneCollection *sc_src);
+bool BKE_collection_move_into(const struct ID *owner_id, struct SceneCollection *sc_dst, struct SceneCollection *sc_src);
typedef void (*BKE_scene_objects_Cb)(struct Object *ob, void *data);
typedef void (*BKE_scene_collections_Cb)(struct SceneCollection *ob, void *data);
@@ -75,11 +82,11 @@ void BKE_scene_objects_iterator_begin(struct BLI_Iterator *iter, void *data_in);
void BKE_scene_objects_iterator_next(struct BLI_Iterator *iter);
void BKE_scene_objects_iterator_end(struct BLI_Iterator *iter);
-#define FOREACH_SCENE_COLLECTION(scene, _instance) \
+#define FOREACH_SCENE_COLLECTION(_id, _instance) \
ITER_BEGIN(BKE_scene_collections_iterator_begin, \
BKE_scene_collections_iterator_next, \
BKE_scene_collections_iterator_end, \
- scene, SceneCollection *, _instance)
+ _id, SceneCollection *, _instance)
#define FOREACH_SCENE_COLLECTION_END \
ITER_END
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index a0d8bdfe60f..31d26d5d4fa 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -156,6 +156,7 @@ struct ARegion *CTX_wm_region(const bContext *C);
void *CTX_wm_region_data(const bContext *C);
struct ARegion *CTX_wm_menu(const bContext *C);
struct wmManipulatorGroup *CTX_wm_manipulator_group(const bContext *C);
+struct wmMsgBus *CTX_wm_message_bus(const bContext *C);
struct ReportList *CTX_wm_reports(const bContext *C);
struct View3D *CTX_wm_view3d(const bContext *C);
@@ -255,7 +256,7 @@ struct LayerCollection *CTX_data_layer_collection(const bContext *C);
struct SceneCollection *CTX_data_scene_collection(const bContext *C);
struct ViewLayer *CTX_data_view_layer(const bContext *C);
struct ViewRender *CTX_data_view_render(const bContext *C);
-struct RenderEngineType *CTX_data_engine(const bContext *C);
+struct RenderEngineType *CTX_data_engine_type(const bContext *C);
struct ToolSettings *CTX_data_tool_settings(const bContext *C);
const char *CTX_data_mode_string(const bContext *C);
diff --git a/source/blender/blenkernel/BKE_group.h b/source/blender/blenkernel/BKE_group.h
index 9aab6950496..ac436876dc4 100644
--- a/source/blender/blenkernel/BKE_group.h
+++ b/source/blender/blenkernel/BKE_group.h
@@ -41,6 +41,7 @@ struct Object;
struct Scene;
void BKE_group_free(struct Group *group);
+void BKE_group_init(struct Group *group);
struct Group *BKE_group_add(struct Main *bmain, const char *name);
void BKE_group_copy_data(struct Main *bmain, struct Group *group_dst, const struct Group *group_src, const int flag);
struct Group *BKE_group_copy(struct Main *bmain, const struct Group *group);
@@ -52,7 +53,26 @@ bool BKE_group_object_exists(struct Group *group, struct Object *ob);
bool BKE_group_object_cyclic_check(struct Main *bmain, struct Object *object, struct Group *group);
bool BKE_group_is_animated(struct Group *group, struct Object *parent);
-void BKE_group_tag_recalc(struct Group *group);
void BKE_group_handle_recalc_and_update(const struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *parent, struct Group *group);
+#define FOREACH_GROUP_BASE(_group, _base) \
+ for (Base *_base = (Base *)(_group)->view_layer->object_bases.first; \
+ _base; \
+ _base = _base->next) \
+ {
+
+#define FOREACH_GROUP_BASE_END \
+ }
+
+#define FOREACH_GROUP_OBJECT(_group, _object) \
+ for (Base *_base = (Base *)(_group)->view_layer->object_bases.first; \
+ _base; \
+ _base = _base->next) \
+ { \
+ Object *_object = _base->object; \
+ BLI_assert(_object != NULL);
+
+#define FOREACH_GROUP_OBJECT_END \
+ }
+
#endif /* __BKE_GROUP_H__ */
diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h
index ecad9c21f99..e4f8b8790f6 100644
--- a/source/blender/blenkernel/BKE_layer.h
+++ b/source/blender/blenkernel/BKE_layer.h
@@ -42,6 +42,7 @@ extern "C" {
struct Base;
struct EvaluationContext;
+struct Group;
struct ID;
struct IDProperty;
struct LayerCollection;
@@ -59,6 +60,7 @@ void BKE_layer_exit(void);
struct ViewLayer *BKE_view_layer_from_scene_get(const struct Scene *scene);
struct ViewLayer *BKE_view_layer_from_workspace_get(const struct Scene *scene, const struct WorkSpace *workspace);
struct ViewLayer *BKE_view_layer_add(struct Scene *scene, const char *name);
+struct ViewLayer *BKE_view_layer_group_add(struct Group *group);
/* DEPRECATED */
struct ViewLayer *BKE_view_layer_context_active_PLACEHOLDER(const struct Scene *scene);
@@ -68,12 +70,17 @@ void BKE_view_layer_free(struct ViewLayer *view_layer);
void BKE_view_layer_selected_objects_tag(struct ViewLayer *view_layer, const int tag);
struct Object *BKE_view_layer_camera_find(struct ViewLayer *view_layer);
-struct ViewLayer *BKE_view_layer_find_from_collection(const struct Scene *scene, struct LayerCollection *lc);
+struct ViewLayer *BKE_view_layer_first_from_id(const struct ID *owner_id);
+struct ViewLayer *BKE_view_layer_find_from_collection(const struct ID *owner_id, struct LayerCollection *lc);
struct Base *BKE_view_layer_base_find(struct ViewLayer *view_layer, struct Object *ob);
-struct Base *BKE_view_layer_base_find_by_name(struct ViewLayer *view_layer, struct Object *ob);
void BKE_view_layer_base_deselect_all(struct ViewLayer *view_layer);
void BKE_view_layer_base_select(struct ViewLayer *view_layer, struct Base *selbase);
+void BKE_view_layer_copy_data(
+ struct ViewLayer *view_layer_dst, struct ViewLayer *view_layer_src,
+ struct SceneCollection *mc_dst, struct SceneCollection *mc_src,
+ const int flag);
+
void BKE_layer_collection_free(struct ViewLayer *view_layer, struct LayerCollection *lc);
struct LayerCollection *BKE_layer_collection_get_active(struct ViewLayer *view_layer);
@@ -84,11 +91,11 @@ int BKE_layer_collection_count(struct ViewLayer *view_layer);
struct LayerCollection *BKE_layer_collection_from_index(struct ViewLayer *view_layer, const int index);
int BKE_layer_collection_findindex(struct ViewLayer *view_layer, const struct LayerCollection *lc);
-bool BKE_layer_collection_move_above(const struct Scene *scene, struct LayerCollection *lc_dst, struct LayerCollection *lc_src);
-bool BKE_layer_collection_move_below(const struct Scene *scene, struct LayerCollection *lc_dst, struct LayerCollection *lc_src);
-bool BKE_layer_collection_move_into(const struct Scene *scene, struct LayerCollection *lc_dst, struct LayerCollection *lc_src);
+bool BKE_layer_collection_move_above(const struct ID *owner_id, struct LayerCollection *lc_dst, struct LayerCollection *lc_src);
+bool BKE_layer_collection_move_below(const struct ID *owner_id, struct LayerCollection *lc_dst, struct LayerCollection *lc_src);
+bool BKE_layer_collection_move_into(const struct ID *owner_id, struct LayerCollection *lc_dst, struct LayerCollection *lc_src);
-void BKE_layer_collection_resync(const struct Scene *scene, const struct SceneCollection *sc);
+void BKE_layer_collection_resync(const struct ID *owner_id, const struct SceneCollection *sc);
struct LayerCollection *BKE_collection_link(struct ViewLayer *view_layer, struct SceneCollection *sc);
@@ -102,13 +109,13 @@ bool BKE_scene_has_object(struct Scene *scene, struct Object *ob);
/* syncing */
-void BKE_layer_sync_new_scene_collection(struct Scene *scene, const struct SceneCollection *sc_parent, struct SceneCollection *sc);
-void BKE_layer_sync_object_link(const struct Scene *scene, struct SceneCollection *sc, struct Object *ob);
-void BKE_layer_sync_object_unlink(const struct Scene *scene, struct SceneCollection *sc, struct Object *ob);
+void BKE_layer_sync_new_scene_collection(struct ID *owner_id, const struct SceneCollection *sc_parent, struct SceneCollection *sc);
+void BKE_layer_sync_object_link(const struct ID *owner_id, struct SceneCollection *sc, struct Object *ob);
+void BKE_layer_sync_object_unlink(const struct ID *owner_id, struct SceneCollection *sc, struct Object *ob);
/* override */
-void BKE_override_view_layer_datablock_add(struct ViewLayer *view_layer, int id_type, const char *data_path, const struct ID *id);
+void BKE_override_view_layer_datablock_add(struct ViewLayer *view_layer, int id_type, const char *data_path, const struct ID *owner_id);
void BKE_override_view_layer_int_add(struct ViewLayer *view_layer, int id_type, const char *data_path, const int value);
void BKE_override_layer_collection_boolean_add(struct LayerCollection *layer_collection, int id_type, const char *data_path, const bool value);
@@ -152,7 +159,7 @@ void BKE_collection_engine_property_value_set_bool(struct IDProperty *props, con
/* evaluation */
void BKE_layer_eval_layer_collection_pre(const struct EvaluationContext *eval_ctx,
- struct Scene *scene,
+ struct ID *owner_id,
struct ViewLayer *view_layer);
void BKE_layer_eval_layer_collection(const struct EvaluationContext *eval_ctx,
struct LayerCollection *layer_collection,
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index f320597ef2d..0abf99415c7 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -77,6 +77,7 @@ enum {
LIB_ID_COPY_CACHES = 1 << 18, /* Copy runtime data caches. */
/* XXX TODO Do we want to keep that? would rather try to get rid of it... */
LIB_ID_COPY_ACTIONS = 1 << 19, /* EXCEPTION! Deep-copy actions used by animdata of copied ID. */
+ LIB_ID_COPY_KEEP_LIB = 1 << 20, /* Keep the library pointer when copying datablock outside of bmain. */
};
void BKE_libblock_copy_ex(struct Main *bmain, const struct ID *id, struct ID **r_newid, const int flag);
@@ -147,6 +148,7 @@ bool id_make_local(struct Main *bmain, struct ID *id, const bool test, const boo
bool id_single_user(struct bContext *C, struct ID *id, struct PointerRNA *ptr, struct PropertyRNA *prop);
bool id_copy(struct Main *bmain, const struct ID *id, struct ID **newid, bool test);
bool BKE_id_copy_ex(struct Main *bmain, const struct ID *id, struct ID **r_newid, const int flag, const bool test);
+void BKE_id_swap(struct Main *bmain, struct ID *id_a, struct ID *id_b);
void id_sort_by_name(struct ListBase *lb, struct ID *id);
void BKE_id_expand_local(struct Main *bmain, struct ID *id);
void BKE_id_copy_ensure_local(struct Main *bmain, const struct ID *old_id, struct ID *new_id);
diff --git a/source/blender/blenkernel/BKE_library_override.h b/source/blender/blenkernel/BKE_library_override.h
new file mode 100644
index 00000000000..1ba009660f2
--- /dev/null
+++ b/source/blender/blenkernel/BKE_library_override.h
@@ -0,0 +1,86 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Bastien Montagne.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BKE_LIBRARY_OVERRIDE_H__
+#define __BKE_LIBRARY_OVERRIDE_H__
+
+/** \file BKE_library_override.h
+ * \ingroup bke
+ * \since December 2016
+ * \author mont29
+ */
+
+struct ID;
+struct IDOverrideStatic;
+struct IDOverrideStaticProperty;
+struct IDOverrideStaticPropertyOperation;
+struct Main;
+
+struct IDOverrideStatic *BKE_override_static_init(struct ID *local_id, struct ID *reference_id);
+void BKE_override_static_copy(struct ID *dst_id, const struct ID *src_id);
+void BKE_override_static_clear(struct IDOverrideStatic *override);
+void BKE_override_static_free(struct IDOverrideStatic **override);
+
+struct ID *BKE_override_static_create_from(struct Main *bmain, struct ID *reference_id);
+
+struct IDOverrideStaticProperty *BKE_override_static_property_find(struct IDOverrideStatic *override, const char *rna_path);
+struct IDOverrideStaticProperty *BKE_override_static_property_get(struct IDOverrideStatic *override, const char *rna_path, bool *r_created);
+void BKE_override_static_property_delete(struct IDOverrideStatic *override, struct IDOverrideStaticProperty *override_property);
+
+struct IDOverrideStaticPropertyOperation *BKE_override_static_property_operation_find(
+ struct IDOverrideStaticProperty *override_property,
+ const char *subitem_refname, const char *subitem_locname,
+ const int subitem_refindex, const int subitem_locindex, const bool strict, bool *r_strict);
+struct IDOverrideStaticPropertyOperation *BKE_override_static_property_operation_get(
+ struct IDOverrideStaticProperty *override_property, const short operation,
+ const char *subitem_refname, const char *subitem_locname,
+ const int subitem_refindex, const int subitem_locindex,
+ const bool strict, bool *r_strict, bool *r_created);
+void BKE_override_static_property_operation_delete(
+ struct IDOverrideStaticProperty *override_property, struct IDOverrideStaticPropertyOperation *override_property_operation);
+
+bool BKE_override_static_status_check_local(struct ID *local);
+bool BKE_override_static_status_check_reference(struct ID *local);
+
+bool BKE_override_static_operations_create(struct ID *local);
+void BKE_main_override_static_operations_create(struct Main *bmain);
+
+void BKE_override_static_update(struct Main *bmain, struct ID *local);
+void BKE_main_override_static_update(struct Main *bmain);
+
+
+/* Storage (.blend file writing) part. */
+
+/* For now, we just use a temp main list. */
+typedef struct Main OverrideStaticStorage;
+
+OverrideStaticStorage *BKE_override_static_operations_store_initialize(void);
+struct ID *BKE_override_static_operations_store_start(OverrideStaticStorage *override_storage, struct ID *local);
+void BKE_override_static_operations_store_end(OverrideStaticStorage *override_storage, struct ID *local);
+void BKE_override_static_operations_store_finalize(OverrideStaticStorage *override_storage);
+
+
+
+#endif /* __BKE_LIBRARY_OVERRIDE_H__ */
diff --git a/source/blender/blenkernel/BKE_library_query.h b/source/blender/blenkernel/BKE_library_query.h
index d6e7d98f371..b66fc0aab16 100644
--- a/source/blender/blenkernel/BKE_library_query.h
+++ b/source/blender/blenkernel/BKE_library_query.h
@@ -56,6 +56,9 @@ enum {
* How to handle that kind of cases totally depends on what caller code is doing... */
IDWALK_CB_LOOPBACK = (1 << 4),
+ /** That ID is used as static override's reference by its owner. */
+ IDWALK_CB_STATIC_OVERRIDE_REFERENCE = (1 << 5),
+
/**
* Adjusts #ID.us reference-count.
* \note keep in sync with 'newlibadr_us' use in readfile.c
diff --git a/source/blender/blenkernel/BKE_library_remap.h b/source/blender/blenkernel/BKE_library_remap.h
index fd37fd762f4..3425ca011b7 100644
--- a/source/blender/blenkernel/BKE_library_remap.h
+++ b/source/blender/blenkernel/BKE_library_remap.h
@@ -51,6 +51,8 @@ enum {
* This is needed e.g. in reload scenario, since we have to ensure remapping of Armature data of local proxy
* is also performed. Usual nightmare... */
ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE = 1 << 4,
+ /* Do not remap static override pointers. */
+ ID_REMAP_SKIP_STATIC_OVERRIDE = 1 << 5,
};
/* Note: Requiring new_id to be non-null, this *may* not be the case ultimately, but makes things simpler for now. */
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index 31125545670..2b183906f57 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -184,7 +184,6 @@ void BKE_object_tfm_protected_restore(struct Object *ob,
/* Dependency graph evaluation callbacks. */
void BKE_object_eval_local_transform(const struct EvaluationContext *eval_ctx,
- struct Scene *scene,
struct Object *ob);
void BKE_object_eval_parent(const struct EvaluationContext *eval_ctx,
struct Scene *scene,
@@ -194,8 +193,9 @@ void BKE_object_eval_constraints(const struct EvaluationContext *eval_ctx,
struct Object *ob);
void BKE_object_eval_done(const struct EvaluationContext *eval_ctx, struct Object *ob);
+bool BKE_object_eval_proxy_copy(const struct EvaluationContext *eval_ct,
+ struct Object *object);
void BKE_object_eval_uber_transform(const struct EvaluationContext *eval_ctx,
- struct Scene *scene,
struct Object *ob);
void BKE_object_eval_uber_data(const struct EvaluationContext *eval_ctx,
struct Scene *scene,
@@ -205,6 +205,10 @@ void BKE_object_eval_cloth(const struct EvaluationContext *eval_ctx,
struct Scene *scene,
struct Object *object);
+void BKE_object_eval_transform_all(const struct EvaluationContext *eval_ctx,
+ struct Scene *scene,
+ struct Object *object);
+
void BKE_object_eval_update_shading(const struct EvaluationContext *eval_ctx,
struct Object *object);
void BKE_object_data_select_update(const struct EvaluationContext *eval_ctx,
@@ -226,6 +230,7 @@ void BKE_object_handle_update_ex(
struct Scene *scene, struct Object *ob,
struct RigidBodyWorld *rbw,
const bool do_proxy_update);
+
void BKE_object_sculpt_modifiers_changed(struct Object *ob);
int BKE_object_obdata_texspace_get(struct Object *ob, short **r_texflag, float **r_loc, float **r_size, float **r_rot);
diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
index fb6d8e7c75e..94d78ae47e3 100644
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -57,6 +57,7 @@ struct wmWindow;
struct wmWindowManager;
struct WorkSpace;
struct GPUFXSettings;
+struct wmMsgBus;
#include "BLI_compiler_attrs.h"
@@ -140,6 +141,12 @@ typedef struct ARegionType {
/* contextual changes should be handled here */
void (*listener)(struct bScreen *, struct ScrArea *, struct ARegion *,
struct wmNotifier *, const struct Scene *scene);
+ /* Optional callback to generate subscriptions. */
+ void (*message_subscribe)(
+ const struct bContext *C,
+ struct WorkSpace *workspace, struct Scene *scene,
+ struct bScreen *sc, struct ScrArea *sa, struct ARegion *ar,
+ struct wmMsgBus *mbus);
void (*free)(struct ARegion *);
diff --git a/source/blender/blenkernel/BKE_workspace.h b/source/blender/blenkernel/BKE_workspace.h
index f295af3150a..9f989f7ae8f 100644
--- a/source/blender/blenkernel/BKE_workspace.h
+++ b/source/blender/blenkernel/BKE_workspace.h
@@ -32,6 +32,7 @@ struct EvaluationContext;
struct Main;
struct Scene;
struct TransformOrientation;
+struct ViewLayer;
/**
* Plan is to store the object-mode per workspace, not per object anymore.
@@ -62,10 +63,17 @@ void BKE_workspace_layout_remove(
struct Main *bmain,
struct WorkSpace *workspace, struct WorkSpaceLayout *layout) ATTR_NONNULL();
+void BKE_workspace_relations_free(
+ ListBase *relation_list);
+
/* -------------------------------------------------------------------- */
/* General Utils */
+void BKE_workspace_view_layer_remove_references(
+ const struct Main *bmain,
+ const struct ViewLayer *view_layer) ATTR_NONNULL();
+
void BKE_workspace_transform_orientation_remove(
struct WorkSpace *workspace, struct TransformOrientation *orientation) ATTR_NONNULL();
struct TransformOrientation *BKE_workspace_transform_orientation_find(
@@ -98,14 +106,24 @@ void BKE_workspace_active_layout_set(struct WorkSpaceInstanceHook *h
struct bScreen *BKE_workspace_active_screen_get(const struct WorkSpaceInstanceHook *hook) GETTER_ATTRS;
void BKE_workspace_active_screen_set(
struct WorkSpaceInstanceHook *hook, struct WorkSpace *workspace, struct bScreen *screen) SETTER_ATTRS;
-enum eObjectMode BKE_workspace_object_mode_get(const struct WorkSpace *workspace) GETTER_ATTRS;
#ifdef USE_WORKSPACE_MODE
-void BKE_workspace_object_mode_set(struct WorkSpace *workspace, const enum eObjectMode mode) SETTER_ATTRS;
+enum eObjectMode BKE_workspace_object_mode_get(
+ const struct WorkSpace *workspace,
+ const struct Scene *scene) GETTER_ATTRS;
+void BKE_workspace_object_mode_set(
+ struct WorkSpace *workspace,
+ struct Scene *scene,
+ const enum eObjectMode mode) SETTER_ATTRS;
#endif
-struct Base *BKE_workspace_active_base_get(const struct WorkSpace *workspace);
+struct Base *BKE_workspace_active_base_get(const struct WorkSpace *workspace, const struct Scene *scene);
struct ListBase *BKE_workspace_transform_orientations_get(struct WorkSpace *workspace) GETTER_ATTRS;
-struct ViewLayer *BKE_workspace_view_layer_get(const struct WorkSpace *workspace) GETTER_ATTRS;
-void BKE_workspace_view_layer_set(struct WorkSpace *workspace, struct ViewLayer *layer) SETTER_ATTRS;
+struct ViewLayer *BKE_workspace_view_layer_get(
+ const struct WorkSpace *workspace,
+ const struct Scene *scene) GETTER_ATTRS;
+void BKE_workspace_view_layer_set(
+ struct WorkSpace *workspace,
+ struct ViewLayer *layer,
+ struct Scene *scene) SETTER_ATTRS;
struct ListBase *BKE_workspace_layouts_get(struct WorkSpace *workspace) GETTER_ATTRS;
const char *BKE_workspace_layout_name_get(const struct WorkSpaceLayout *layout) GETTER_ATTRS;
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 24b0adb1adb..c99c3d6ffa9 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -124,6 +124,7 @@ set(SRC
intern/lattice.c
intern/library.c
intern/library_idmap.c
+ intern/library_override.c
intern/library_query.c
intern/library_remap.c
intern/linestyle.c
@@ -256,6 +257,7 @@ set(SRC
BKE_lattice.h
BKE_library.h
BKE_library_idmap.h
+ BKE_library_override.h
BKE_library_query.h
BKE_library_remap.h
BKE_linestyle.h
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_legacy.c b/source/blender/blenkernel/intern/CCGSubSurf_legacy.c
index e9002af19b1..f68d1a2697c 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_legacy.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf_legacy.c
@@ -27,6 +27,7 @@
#include "BLI_utildefines.h" /* for BLI_assert */
#include "BLI_math.h"
+#include "BLI_task.h"
#include "CCGSubSurf.h"
#include "CCGSubSurf_intern.h"
@@ -121,179 +122,251 @@ static float EDGE_getSharpness(CCGEdge *e, int lvl)
return e->crease - lvl;
}
-static void ccgSubSurf__calcVertNormals(CCGSubSurf *ss,
- CCGVert **effectedV, CCGEdge **effectedE, CCGFace **effectedF,
- int numEffectedV, int numEffectedE, int numEffectedF)
+
+
+typedef struct CCGSubSurfCalcSubdivData {
+ CCGSubSurf *ss;
+ CCGVert **effectedV;
+ CCGEdge **effectedE;
+ CCGFace **effectedF;
+ int numEffectedV;
+ int numEffectedE;
+ int numEffectedF;
+
+ int curLvl;
+} CCGSubSurfCalcSubdivData;
+
+static void ccgSubSurf__calcVertNormals_faces_accumulate_cb(void *userdata, int ptrIdx)
{
- int i, ptrIdx;
- int subdivLevels = ss->subdivLevels;
- int lvl = ss->subdivLevels;
- int edgeSize = ccg_edgesize(lvl);
- int gridSize = ccg_gridsize(lvl);
- int normalDataOffset = ss->normalDataOffset;
- int vertDataSize = ss->meshIFC.vertDataSize;
+ CCGSubSurfCalcSubdivData *data = userdata;
-#pragma omp parallel for private(ptrIdx) if (numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT)
- for (ptrIdx = 0; ptrIdx < numEffectedF; ptrIdx++) {
- CCGFace *f = (CCGFace *) effectedF[ptrIdx];
- int S, x, y;
- float no[3];
+ CCGSubSurf *ss = data->ss;
+ CCGFace *f = data->effectedF[ptrIdx];
- for (S = 0; S < f->numVerts; S++) {
- for (y = 0; y < gridSize - 1; y++) {
- for (x = 0; x < gridSize - 1; x++) {
- NormZero(FACE_getIFNo(f, lvl, S, x, y));
- }
- }
+ const int subdivLevels = ss->subdivLevels;
+ const int lvl = ss->subdivLevels;
+ const int gridSize = ccg_gridsize(lvl);
+ const int normalDataOffset = ss->normalDataOffset;
+ const int vertDataSize = ss->meshIFC.vertDataSize;
- if (FACE_getEdges(f)[(S - 1 + f->numVerts) % f->numVerts]->flags & Edge_eEffected) {
- for (x = 0; x < gridSize - 1; x++) {
- NormZero(FACE_getIFNo(f, lvl, S, x, gridSize - 1));
- }
+ int S, x, y;
+ float no[3];
+
+ for (S = 0; S < f->numVerts; S++) {
+ for (y = 0; y < gridSize - 1; y++) {
+ for (x = 0; x < gridSize - 1; x++) {
+ NormZero(FACE_getIFNo(f, lvl, S, x, y));
}
- if (FACE_getEdges(f)[S]->flags & Edge_eEffected) {
- for (y = 0; y < gridSize - 1; y++) {
- NormZero(FACE_getIFNo(f, lvl, S, gridSize - 1, y));
- }
+ }
+
+ if (FACE_getEdges(f)[(S - 1 + f->numVerts) % f->numVerts]->flags & Edge_eEffected) {
+ for (x = 0; x < gridSize - 1; x++) {
+ NormZero(FACE_getIFNo(f, lvl, S, x, gridSize - 1));
}
- if (FACE_getVerts(f)[S]->flags & Vert_eEffected) {
- NormZero(FACE_getIFNo(f, lvl, S, gridSize - 1, gridSize - 1));
+ }
+ if (FACE_getEdges(f)[S]->flags & Edge_eEffected) {
+ for (y = 0; y < gridSize - 1; y++) {
+ NormZero(FACE_getIFNo(f, lvl, S, gridSize - 1, y));
}
}
+ if (FACE_getVerts(f)[S]->flags & Vert_eEffected) {
+ NormZero(FACE_getIFNo(f, lvl, S, gridSize - 1, gridSize - 1));
+ }
+ }
- for (S = 0; S < f->numVerts; S++) {
- int yLimit = !(FACE_getEdges(f)[(S - 1 + f->numVerts) % f->numVerts]->flags & Edge_eEffected);
- int xLimit = !(FACE_getEdges(f)[S]->flags & Edge_eEffected);
- int yLimitNext = xLimit;
- int xLimitPrev = yLimit;
-
- for (y = 0; y < gridSize - 1; y++) {
- for (x = 0; x < gridSize - 1; x++) {
- int xPlusOk = (!xLimit || x < gridSize - 2);
- int yPlusOk = (!yLimit || y < gridSize - 2);
-
- FACE_calcIFNo(f, lvl, S, x, y, no);
-
- NormAdd(FACE_getIFNo(f, lvl, S, x + 0, y + 0), no);
- if (xPlusOk)
- NormAdd(FACE_getIFNo(f, lvl, S, x + 1, y + 0), no);
- if (yPlusOk)
- NormAdd(FACE_getIFNo(f, lvl, S, x + 0, y + 1), no);
- if (xPlusOk && yPlusOk) {
- if (x < gridSize - 2 || y < gridSize - 2 || FACE_getVerts(f)[S]->flags & Vert_eEffected) {
- NormAdd(FACE_getIFNo(f, lvl, S, x + 1, y + 1), no);
- }
+ for (S = 0; S < f->numVerts; S++) {
+ int yLimit = !(FACE_getEdges(f)[(S - 1 + f->numVerts) % f->numVerts]->flags & Edge_eEffected);
+ int xLimit = !(FACE_getEdges(f)[S]->flags & Edge_eEffected);
+ int yLimitNext = xLimit;
+ int xLimitPrev = yLimit;
+
+ for (y = 0; y < gridSize - 1; y++) {
+ for (x = 0; x < gridSize - 1; x++) {
+ int xPlusOk = (!xLimit || x < gridSize - 2);
+ int yPlusOk = (!yLimit || y < gridSize - 2);
+
+ FACE_calcIFNo(f, lvl, S, x, y, no);
+
+ NormAdd(FACE_getIFNo(f, lvl, S, x + 0, y + 0), no);
+ if (xPlusOk)
+ NormAdd(FACE_getIFNo(f, lvl, S, x + 1, y + 0), no);
+ if (yPlusOk)
+ NormAdd(FACE_getIFNo(f, lvl, S, x + 0, y + 1), no);
+ if (xPlusOk && yPlusOk) {
+ if (x < gridSize - 2 || y < gridSize - 2 || FACE_getVerts(f)[S]->flags & Vert_eEffected) {
+ NormAdd(FACE_getIFNo(f, lvl, S, x + 1, y + 1), no);
}
+ }
- if (x == 0 && y == 0) {
- int K;
+ if (x == 0 && y == 0) {
+ int K;
- if (!yLimitNext || 1 < gridSize - 1)
- NormAdd(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, 1), no);
- if (!xLimitPrev || 1 < gridSize - 1)
- NormAdd(FACE_getIFNo(f, lvl, (S - 1 + f->numVerts) % f->numVerts, 1, 0), no);
+ if (!yLimitNext || 1 < gridSize - 1)
+ NormAdd(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, 1), no);
+ if (!xLimitPrev || 1 < gridSize - 1)
+ NormAdd(FACE_getIFNo(f, lvl, (S - 1 + f->numVerts) % f->numVerts, 1, 0), no);
- for (K = 0; K < f->numVerts; K++) {
- if (K != S) {
- NormAdd(FACE_getIFNo(f, lvl, K, 0, 0), no);
- }
+ for (K = 0; K < f->numVerts; K++) {
+ if (K != S) {
+ NormAdd(FACE_getIFNo(f, lvl, K, 0, 0), no);
}
}
- else if (y == 0) {
- NormAdd(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, x), no);
- if (!yLimitNext || x < gridSize - 2)
- NormAdd(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, x + 1), no);
- }
- else if (x == 0) {
- NormAdd(FACE_getIFNo(f, lvl, (S - 1 + f->numVerts) % f->numVerts, y, 0), no);
- if (!xLimitPrev || y < gridSize - 2)
- NormAdd(FACE_getIFNo(f, lvl, (S - 1 + f->numVerts) % f->numVerts, y + 1, 0), no);
- }
+ }
+ else if (y == 0) {
+ NormAdd(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, x), no);
+ if (!yLimitNext || x < gridSize - 2)
+ NormAdd(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, x + 1), no);
+ }
+ else if (x == 0) {
+ NormAdd(FACE_getIFNo(f, lvl, (S - 1 + f->numVerts) % f->numVerts, y, 0), no);
+ if (!xLimitPrev || y < gridSize - 2)
+ NormAdd(FACE_getIFNo(f, lvl, (S - 1 + f->numVerts) % f->numVerts, y + 1, 0), no);
}
}
}
}
- /* XXX can I reduce the number of normalisations here? */
- for (ptrIdx = 0; ptrIdx < numEffectedV; ptrIdx++) {
- CCGVert *v = (CCGVert *) effectedV[ptrIdx];
- float *no = VERT_getNo(v, lvl);
+}
- NormZero(no);
+static void ccgSubSurf__calcVertNormals_faces_finalize_cb(void *userdata, int ptrIdx)
+{
+ CCGSubSurfCalcSubdivData *data = userdata;
- for (i = 0; i < v->numFaces; i++) {
- CCGFace *f = v->faces[i];
- NormAdd(no, FACE_getIFNo(f, lvl, ccg_face_getVertIndex(f, v), gridSize - 1, gridSize - 1));
- }
+ CCGSubSurf *ss = data->ss;
+ CCGFace *f = data->effectedF[ptrIdx];
- if (UNLIKELY(v->numFaces == 0)) {
- NormCopy(no, VERT_getCo(v, lvl));
+ const int subdivLevels = ss->subdivLevels;
+ const int lvl = ss->subdivLevels;
+ const int gridSize = ccg_gridsize(lvl);
+ const int normalDataOffset = ss->normalDataOffset;
+ const int vertDataSize = ss->meshIFC.vertDataSize;
+
+ int S, x, y;
+
+ for (S = 0; S < f->numVerts; S++) {
+ NormCopy(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, gridSize - 1),
+ FACE_getIFNo(f, lvl, S, gridSize - 1, 0));
+ }
+
+ for (S = 0; S < f->numVerts; S++) {
+ for (y = 0; y < gridSize; y++) {
+ for (x = 0; x < gridSize; x++) {
+ float *no = FACE_getIFNo(f, lvl, S, x, y);
+ Normalize(no);
+ }
}
- Normalize(no);
+ VertDataCopy((float *)((byte *)FACE_getCenterData(f) + normalDataOffset),
+ FACE_getIFNo(f, lvl, S, 0, 0), ss);
- for (i = 0; i < v->numFaces; i++) {
- CCGFace *f = v->faces[i];
- NormCopy(FACE_getIFNo(f, lvl, ccg_face_getVertIndex(f, v), gridSize - 1, gridSize - 1), no);
+ for (x = 1; x < gridSize - 1; x++) {
+ NormCopy(FACE_getIENo(f, lvl, S, x),
+ FACE_getIFNo(f, lvl, S, x, 0));
}
}
- for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) {
- CCGEdge *e = (CCGEdge *) effectedE[ptrIdx];
+}
- if (e->numFaces) {
- CCGFace *fLast = e->faces[e->numFaces - 1];
- int x;
+static void ccgSubSurf__calcVertNormals_edges_accumulate_cb(void *userdata, int ptrIdx)
+{
+ CCGSubSurfCalcSubdivData *data = userdata;
- for (i = 0; i < e->numFaces - 1; i++) {
- CCGFace *f = e->faces[i];
- const int f_ed_idx = ccg_face_getEdgeIndex(f, e);
- const int f_ed_idx_last = ccg_face_getEdgeIndex(fLast, e);
+ CCGSubSurf *ss = data->ss;
+ CCGEdge *e = data->effectedE[ptrIdx];
- for (x = 1; x < edgeSize - 1; x++) {
- NormAdd(_face_getIFNoEdge(fLast, e, f_ed_idx_last, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset),
- _face_getIFNoEdge(f, e, f_ed_idx, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset));
- }
+ const int subdivLevels = ss->subdivLevels;
+ const int lvl = ss->subdivLevels;
+ const int edgeSize = ccg_edgesize(lvl);
+ const int normalDataOffset = ss->normalDataOffset;
+ const int vertDataSize = ss->meshIFC.vertDataSize;
+
+ if (e->numFaces) {
+ CCGFace *fLast = e->faces[e->numFaces - 1];
+ int x, i;
+
+ for (i = 0; i < e->numFaces - 1; i++) {
+ CCGFace *f = e->faces[i];
+ const int f_ed_idx = ccg_face_getEdgeIndex(f, e);
+ const int f_ed_idx_last = ccg_face_getEdgeIndex(fLast, e);
+
+ for (x = 1; x < edgeSize - 1; x++) {
+ NormAdd(_face_getIFNoEdge(fLast, e, f_ed_idx_last, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset),
+ _face_getIFNoEdge(f, e, f_ed_idx, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset));
}
+ }
- for (i = 0; i < e->numFaces - 1; i++) {
- CCGFace *f = e->faces[i];
- const int f_ed_idx = ccg_face_getEdgeIndex(f, e);
- const int f_ed_idx_last = ccg_face_getEdgeIndex(fLast, e);
+ for (i = 0; i < e->numFaces - 1; i++) {
+ CCGFace *f = e->faces[i];
+ const int f_ed_idx = ccg_face_getEdgeIndex(f, e);
+ const int f_ed_idx_last = ccg_face_getEdgeIndex(fLast, e);
- for (x = 1; x < edgeSize - 1; x++) {
- NormCopy(_face_getIFNoEdge(f, e, f_ed_idx, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset),
- _face_getIFNoEdge(fLast, e, f_ed_idx_last, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset));
- }
+ for (x = 1; x < edgeSize - 1; x++) {
+ NormCopy(_face_getIFNoEdge(f, e, f_ed_idx, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset),
+ _face_getIFNoEdge(fLast, e, f_ed_idx_last, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset));
}
}
}
+}
-#pragma omp parallel for private(ptrIdx) if (numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT)
- for (ptrIdx = 0; ptrIdx < numEffectedF; ptrIdx++) {
- CCGFace *f = (CCGFace *) effectedF[ptrIdx];
- int S, x, y;
+static void ccgSubSurf__calcVertNormals(CCGSubSurf *ss,
+ CCGVert **effectedV, CCGEdge **effectedE, CCGFace **effectedF,
+ int numEffectedV, int numEffectedE, int numEffectedF)
+{
+ int i, ptrIdx;
+ const int subdivLevels = ss->subdivLevels;
+ const int lvl = ss->subdivLevels;
+ const int edgeSize = ccg_edgesize(lvl);
+ const int gridSize = ccg_gridsize(lvl);
+ const int normalDataOffset = ss->normalDataOffset;
+ const int vertDataSize = ss->meshIFC.vertDataSize;
+
+ CCGSubSurfCalcSubdivData data = {
+ .ss = ss,
+ .effectedV = effectedV,
+ .effectedE = effectedE,
+ .effectedF = effectedF,
+ .numEffectedV = numEffectedV,
+ .numEffectedE = numEffectedE,
+ .numEffectedF = numEffectedF
+ };
+
+ BLI_task_parallel_range(0, numEffectedF,
+ &data,
+ ccgSubSurf__calcVertNormals_faces_accumulate_cb,
+ numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT);
- for (S = 0; S < f->numVerts; S++) {
- NormCopy(FACE_getIFNo(f, lvl, (S + 1) % f->numVerts, 0, gridSize - 1),
- FACE_getIFNo(f, lvl, S, gridSize - 1, 0));
+ /* XXX can I reduce the number of normalisations here? */
+ for (ptrIdx = 0; ptrIdx < numEffectedV; ptrIdx++) {
+ CCGVert *v = (CCGVert *) effectedV[ptrIdx];
+ float *no = VERT_getNo(v, lvl);
+
+ NormZero(no);
+
+ for (i = 0; i < v->numFaces; i++) {
+ CCGFace *f = v->faces[i];
+ NormAdd(no, FACE_getIFNo(f, lvl, ccg_face_getVertIndex(f, v), gridSize - 1, gridSize - 1));
}
- for (S = 0; S < f->numVerts; S++) {
- for (y = 0; y < gridSize; y++) {
- for (x = 0; x < gridSize; x++) {
- float *no = FACE_getIFNo(f, lvl, S, x, y);
- Normalize(no);
- }
- }
+ if (UNLIKELY(v->numFaces == 0)) {
+ NormCopy(no, VERT_getCo(v, lvl));
+ }
- VertDataCopy((float *)((byte *)FACE_getCenterData(f) + normalDataOffset),
- FACE_getIFNo(f, lvl, S, 0, 0), ss);
+ Normalize(no);
- for (x = 1; x < gridSize - 1; x++)
- NormCopy(FACE_getIENo(f, lvl, S, x),
- FACE_getIFNo(f, lvl, S, x, 0));
+ for (i = 0; i < v->numFaces; i++) {
+ CCGFace *f = v->faces[i];
+ NormCopy(FACE_getIFNo(f, lvl, ccg_face_getVertIndex(f, v), gridSize - 1, gridSize - 1), no);
}
}
+ BLI_task_parallel_range(0, numEffectedE,
+ &data,
+ ccgSubSurf__calcVertNormals_edges_accumulate_cb,
+ numEffectedE * edgeSize * 4 >= CCG_OMP_LIMIT);
+
+ BLI_task_parallel_range(0, numEffectedF,
+ &data,
+ ccgSubSurf__calcVertNormals_faces_finalize_cb,
+ numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT);
+
for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) {
CCGEdge *e = (CCGEdge *) effectedE[ptrIdx];
@@ -322,100 +395,268 @@ static void ccgSubSurf__calcVertNormals(CCGSubSurf *ss,
}
}
-static void ccgSubSurf__calcSubdivLevel(
- CCGSubSurf *ss,
- CCGVert **effectedV, CCGEdge **effectedE, CCGFace **effectedF,
- const int numEffectedV, const int numEffectedE, const int numEffectedF, const int curLvl)
+
+static void ccgSubSurf__calcSubdivLevel_interior_faces_edges_midpoints_cb(void *userdata, int ptrIdx)
{
+ CCGSubSurfCalcSubdivData *data = userdata;
+
+ CCGSubSurf *ss = data->ss;
+ CCGFace *f = data->effectedF[ptrIdx];
+
const int subdivLevels = ss->subdivLevels;
+ const int curLvl = data->curLvl;
const int nextLvl = curLvl + 1;
- int edgeSize = ccg_edgesize(curLvl);
- int gridSize = ccg_gridsize(curLvl);
- int ptrIdx, i;
- int vertDataSize = ss->meshIFC.vertDataSize;
- float *q = ss->q, *r = ss->r;
+ const int gridSize = ccg_gridsize(curLvl);
+ const int vertDataSize = ss->meshIFC.vertDataSize;
-#pragma omp parallel for private(ptrIdx) if (numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT)
- for (ptrIdx = 0; ptrIdx < numEffectedF; ptrIdx++) {
- CCGFace *f = (CCGFace *) effectedF[ptrIdx];
- int S, x, y;
+ int S, x, y;
- /* interior face midpoints
+ /* interior face midpoints
+ * - old interior face points
+ */
+ for (S = 0; S < f->numVerts; S++) {
+ for (y = 0; y < gridSize - 1; y++) {
+ for (x = 0; x < gridSize - 1; x++) {
+ int fx = 1 + 2 * x;
+ int fy = 1 + 2 * y;
+ const float *co0 = FACE_getIFCo(f, curLvl, S, x + 0, y + 0);
+ const float *co1 = FACE_getIFCo(f, curLvl, S, x + 1, y + 0);
+ const float *co2 = FACE_getIFCo(f, curLvl, S, x + 1, y + 1);
+ const float *co3 = FACE_getIFCo(f, curLvl, S, x + 0, y + 1);
+ float *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
+
+ VertDataAvg4(co, co0, co1, co2, co3, ss);
+ }
+ }
+ }
+
+ /* interior edge midpoints
+ * - old interior edge points
+ * - new interior face midpoints
+ */
+ for (S = 0; S < f->numVerts; S++) {
+ for (x = 0; x < gridSize - 1; x++) {
+ int fx = x * 2 + 1;
+ const float *co0 = FACE_getIECo(f, curLvl, S, x + 0);
+ const float *co1 = FACE_getIECo(f, curLvl, S, x + 1);
+ const float *co2 = FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx);
+ const float *co3 = FACE_getIFCo(f, nextLvl, S, fx, 1);
+ float *co = FACE_getIECo(f, nextLvl, S, fx);
+
+ VertDataAvg4(co, co0, co1, co2, co3, ss);
+ }
+
+ /* interior face interior edge midpoints
* - old interior face points
+ * - new interior face midpoints
*/
- for (S = 0; S < f->numVerts; S++) {
+
+ /* vertical */
+ for (x = 1; x < gridSize - 1; x++) {
for (y = 0; y < gridSize - 1; y++) {
- for (x = 0; x < gridSize - 1; x++) {
- int fx = 1 + 2 * x;
- int fy = 1 + 2 * y;
- const float *co0 = FACE_getIFCo(f, curLvl, S, x + 0, y + 0);
- const float *co1 = FACE_getIFCo(f, curLvl, S, x + 1, y + 0);
- const float *co2 = FACE_getIFCo(f, curLvl, S, x + 1, y + 1);
- const float *co3 = FACE_getIFCo(f, curLvl, S, x + 0, y + 1);
- float *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
-
- VertDataAvg4(co, co0, co1, co2, co3, ss);
- }
+ int fx = x * 2;
+ int fy = y * 2 + 1;
+ const float *co0 = FACE_getIFCo(f, curLvl, S, x, y + 0);
+ const float *co1 = FACE_getIFCo(f, curLvl, S, x, y + 1);
+ const float *co2 = FACE_getIFCo(f, nextLvl, S, fx - 1, fy);
+ const float *co3 = FACE_getIFCo(f, nextLvl, S, fx + 1, fy);
+ float *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
+
+ VertDataAvg4(co, co0, co1, co2, co3, ss);
}
}
- /* interior edge midpoints
- * - old interior edge points
- * - new interior face midpoints
- */
- for (S = 0; S < f->numVerts; S++) {
+ /* horizontal */
+ for (y = 1; y < gridSize - 1; y++) {
for (x = 0; x < gridSize - 1; x++) {
int fx = x * 2 + 1;
- const float *co0 = FACE_getIECo(f, curLvl, S, x + 0);
- const float *co1 = FACE_getIECo(f, curLvl, S, x + 1);
- const float *co2 = FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx);
- const float *co3 = FACE_getIFCo(f, nextLvl, S, fx, 1);
- float *co = FACE_getIECo(f, nextLvl, S, fx);
-
+ int fy = y * 2;
+ const float *co0 = FACE_getIFCo(f, curLvl, S, x + 0, y);
+ const float *co1 = FACE_getIFCo(f, curLvl, S, x + 1, y);
+ const float *co2 = FACE_getIFCo(f, nextLvl, S, fx, fy - 1);
+ const float *co3 = FACE_getIFCo(f, nextLvl, S, fx, fy + 1);
+ float *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
+
VertDataAvg4(co, co0, co1, co2, co3, ss);
}
+ }
+ }
+}
- /* interior face interior edge midpoints
- * - old interior face points
- * - new interior face midpoints
- */
-
- /* vertical */
- for (x = 1; x < gridSize - 1; x++) {
- for (y = 0; y < gridSize - 1; y++) {
- int fx = x * 2;
- int fy = y * 2 + 1;
- const float *co0 = FACE_getIFCo(f, curLvl, S, x, y + 0);
- const float *co1 = FACE_getIFCo(f, curLvl, S, x, y + 1);
- const float *co2 = FACE_getIFCo(f, nextLvl, S, fx - 1, fy);
- const float *co3 = FACE_getIFCo(f, nextLvl, S, fx + 1, fy);
- float *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
-
- VertDataAvg4(co, co0, co1, co2, co3, ss);
- }
- }
+static void ccgSubSurf__calcSubdivLevel_interior_faces_edges_centerpoints_shift_cb(void *userdata, int ptrIdx)
+{
+ CCGSubSurfCalcSubdivData *data = userdata;
+
+ CCGSubSurf *ss = data->ss;
+ CCGFace *f = data->effectedF[ptrIdx];
+
+ const int subdivLevels = ss->subdivLevels;
+ const int curLvl = data->curLvl;
+ const int nextLvl = curLvl + 1;
+ const int gridSize = ccg_gridsize(curLvl);
+ const int vertDataSize = ss->meshIFC.vertDataSize;
+
+ float *q_thread = alloca(vertDataSize);
+ float *r_thread = alloca(vertDataSize);
- /* horizontal */
+ int S, x, y;
+
+ /* interior center point shift
+ * - old face center point (shifting)
+ * - old interior edge points
+ * - new interior face midpoints
+ */
+ VertDataZero(q_thread, ss);
+ for (S = 0; S < f->numVerts; S++) {
+ VertDataAdd(q_thread, FACE_getIFCo(f, nextLvl, S, 1, 1), ss);
+ }
+ VertDataMulN(q_thread, 1.0f / f->numVerts, ss);
+ VertDataZero(r_thread, ss);
+ for (S = 0; S < f->numVerts; S++) {
+ VertDataAdd(r_thread, FACE_getIECo(f, curLvl, S, 1), ss);
+ }
+ VertDataMulN(r_thread, 1.0f / f->numVerts, ss);
+
+ VertDataMulN((float *)FACE_getCenterData(f), f->numVerts - 2.0f, ss);
+ VertDataAdd((float *)FACE_getCenterData(f), q_thread, ss);
+ VertDataAdd((float *)FACE_getCenterData(f), r_thread, ss);
+ VertDataMulN((float *)FACE_getCenterData(f), 1.0f / f->numVerts, ss);
+
+ for (S = 0; S < f->numVerts; S++) {
+ /* interior face shift
+ * - old interior face point (shifting)
+ * - new interior edge midpoints
+ * - new interior face midpoints
+ */
+ for (x = 1; x < gridSize - 1; x++) {
for (y = 1; y < gridSize - 1; y++) {
- for (x = 0; x < gridSize - 1; x++) {
- int fx = x * 2 + 1;
- int fy = y * 2;
- const float *co0 = FACE_getIFCo(f, curLvl, S, x + 0, y);
- const float *co1 = FACE_getIFCo(f, curLvl, S, x + 1, y);
- const float *co2 = FACE_getIFCo(f, nextLvl, S, fx, fy - 1);
- const float *co3 = FACE_getIFCo(f, nextLvl, S, fx, fy + 1);
- float *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
-
- VertDataAvg4(co, co0, co1, co2, co3, ss);
- }
+ int fx = x * 2;
+ int fy = y * 2;
+ const float *co = FACE_getIFCo(f, curLvl, S, x, y);
+ float *nCo = FACE_getIFCo(f, nextLvl, S, fx, fy);
+
+ VertDataAvg4(q_thread,
+ FACE_getIFCo(f, nextLvl, S, fx - 1, fy - 1),
+ FACE_getIFCo(f, nextLvl, S, fx + 1, fy - 1),
+ FACE_getIFCo(f, nextLvl, S, fx + 1, fy + 1),
+ FACE_getIFCo(f, nextLvl, S, fx - 1, fy + 1),
+ ss);
+
+ VertDataAvg4(r_thread,
+ FACE_getIFCo(f, nextLvl, S, fx - 1, fy + 0),
+ FACE_getIFCo(f, nextLvl, S, fx + 1, fy + 0),
+ FACE_getIFCo(f, nextLvl, S, fx + 0, fy - 1),
+ FACE_getIFCo(f, nextLvl, S, fx + 0, fy + 1),
+ ss);
+
+ VertDataCopy(nCo, co, ss);
+ VertDataSub(nCo, q_thread, ss);
+ VertDataMulN(nCo, 0.25f, ss);
+ VertDataAdd(nCo, r_thread, ss);
}
}
+
+ /* interior edge interior shift
+ * - old interior edge point (shifting)
+ * - new interior edge midpoints
+ * - new interior face midpoints
+ */
+ for (x = 1; x < gridSize - 1; x++) {
+ int fx = x * 2;
+ const float *co = FACE_getIECo(f, curLvl, S, x);
+ float *nCo = FACE_getIECo(f, nextLvl, S, fx);
+
+ VertDataAvg4(q_thread,
+ FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx - 1),
+ FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx + 1),
+ FACE_getIFCo(f, nextLvl, S, fx + 1, +1),
+ FACE_getIFCo(f, nextLvl, S, fx - 1, +1),
+ ss);
+
+ VertDataAvg4(r_thread,
+ FACE_getIECo(f, nextLvl, S, fx - 1),
+ FACE_getIECo(f, nextLvl, S, fx + 1),
+ FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx),
+ FACE_getIFCo(f, nextLvl, S, fx, 1),
+ ss);
+
+ VertDataCopy(nCo, co, ss);
+ VertDataSub(nCo, q_thread, ss);
+ VertDataMulN(nCo, 0.25f, ss);
+ VertDataAdd(nCo, r_thread, ss);
+ }
}
+}
+
+static void ccgSubSurf__calcSubdivLevel_verts_copydata_cb(void *userdata, int ptrIdx)
+{
+ CCGSubSurfCalcSubdivData *data = userdata;
+
+ CCGSubSurf *ss = data->ss;
+ CCGFace *f = data->effectedF[ptrIdx];
+
+ const int subdivLevels = ss->subdivLevels;
+ const int nextLvl = data->curLvl + 1;
+ const int gridSize = ccg_gridsize(nextLvl);
+ const int cornerIdx = gridSize - 1;
+ const int vertDataSize = ss->meshIFC.vertDataSize;
+
+ int S, x;
+
+ for (S = 0; S < f->numVerts; S++) {
+ CCGEdge *e = FACE_getEdges(f)[S];
+ CCGEdge *prevE = FACE_getEdges(f)[(S + f->numVerts - 1) % f->numVerts];
+
+ VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), (float *)FACE_getCenterData(f), ss);
+ VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), (float *)FACE_getCenterData(f), ss);
+ VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], nextLvl), ss);
+ VertDataCopy(FACE_getIECo(f, nextLvl, S, cornerIdx), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, cornerIdx), ss);
+ for (x = 1; x < gridSize - 1; x++) {
+ float *co = FACE_getIECo(f, nextLvl, S, x);
+ VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, 0), co, ss);
+ VertDataCopy(FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 0, x), co, ss);
+ }
+ for (x = 0; x < gridSize - 1; x++) {
+ int eI = gridSize - 1 - x;
+ VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, x), _edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, eI, vertDataSize), ss);
+ VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, eI, vertDataSize), ss);
+ }
+ }
+}
+
+static void ccgSubSurf__calcSubdivLevel(
+ CCGSubSurf *ss,
+ CCGVert **effectedV, CCGEdge **effectedE, CCGFace **effectedF,
+ const int numEffectedV, const int numEffectedE, const int numEffectedF, const int curLvl)
+{
+ const int subdivLevels = ss->subdivLevels;
+ const int nextLvl = curLvl + 1;
+ int edgeSize = ccg_edgesize(curLvl);
+ int ptrIdx, i;
+ const int vertDataSize = ss->meshIFC.vertDataSize;
+ float *q = ss->q, *r = ss->r;
+
+ CCGSubSurfCalcSubdivData data = {
+ .ss = ss,
+ .effectedV = effectedV,
+ .effectedE = effectedE,
+ .effectedF = effectedF,
+ .numEffectedV = numEffectedV,
+ .numEffectedE = numEffectedE,
+ .numEffectedF = numEffectedF,
+ .curLvl = curLvl
+ };
+
+ BLI_task_parallel_range(0, numEffectedF,
+ &data,
+ ccgSubSurf__calcSubdivLevel_interior_faces_edges_midpoints_cb,
+ numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT);
/* exterior edge midpoints
* - old exterior edge points
* - new interior face midpoints
*/
+ /* Not worth parallelizing. */
for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) {
CCGEdge *e = (CCGEdge *) effectedE[ptrIdx];
float sharpness = EDGE_getSharpness(e, curLvl);
@@ -470,6 +711,7 @@ static void ccgSubSurf__calcSubdivLevel(
* - old exterior edge points
* - new interior face midpoints
*/
+ /* Not worth parallelizing. */
for (ptrIdx = 0; ptrIdx < numEffectedV; ptrIdx++) {
CCGVert *v = (CCGVert *) effectedV[ptrIdx];
const float *co = VERT_getCo(v, curLvl);
@@ -600,6 +842,7 @@ static void ccgSubSurf__calcSubdivLevel(
* - old exterior edge midpoints
* - new interior face midpoints
*/
+ /* Not worth parallelizing. */
for (ptrIdx = 0; ptrIdx < numEffectedE; ptrIdx++) {
CCGEdge *e = (CCGEdge *) effectedE[ptrIdx];
float sharpness = EDGE_getSharpness(e, curLvl);
@@ -682,151 +925,25 @@ static void ccgSubSurf__calcSubdivLevel(
}
}
-#pragma omp parallel private(ptrIdx) if (numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT)
- {
- float *q_thread, *r_thread;
-
-#pragma omp critical
- {
- q_thread = MEM_mallocN(ss->meshIFC.vertDataSize, "CCGSubsurf q");
- r_thread = MEM_mallocN(ss->meshIFC.vertDataSize, "CCGSubsurf r");
- }
-
-#pragma omp for schedule(static)
- for (ptrIdx = 0; ptrIdx < numEffectedF; ptrIdx++) {
- CCGFace *f = (CCGFace *) effectedF[ptrIdx];
- int S, x, y;
-
- /* interior center point shift
- * - old face center point (shifting)
- * - old interior edge points
- * - new interior face midpoints
- */
- VertDataZero(q_thread, ss);
- for (S = 0; S < f->numVerts; S++) {
- VertDataAdd(q_thread, FACE_getIFCo(f, nextLvl, S, 1, 1), ss);
- }
- VertDataMulN(q_thread, 1.0f / f->numVerts, ss);
- VertDataZero(r_thread, ss);
- for (S = 0; S < f->numVerts; S++) {
- VertDataAdd(r_thread, FACE_getIECo(f, curLvl, S, 1), ss);
- }
- VertDataMulN(r_thread, 1.0f / f->numVerts, ss);
-
- VertDataMulN((float *)FACE_getCenterData(f), f->numVerts - 2.0f, ss);
- VertDataAdd((float *)FACE_getCenterData(f), q_thread, ss);
- VertDataAdd((float *)FACE_getCenterData(f), r_thread, ss);
- VertDataMulN((float *)FACE_getCenterData(f), 1.0f / f->numVerts, ss);
-
- for (S = 0; S < f->numVerts; S++) {
- /* interior face shift
- * - old interior face point (shifting)
- * - new interior edge midpoints
- * - new interior face midpoints
- */
- for (x = 1; x < gridSize - 1; x++) {
- for (y = 1; y < gridSize - 1; y++) {
- int fx = x * 2;
- int fy = y * 2;
- const float *co = FACE_getIFCo(f, curLvl, S, x, y);
- float *nCo = FACE_getIFCo(f, nextLvl, S, fx, fy);
-
- VertDataAvg4(q_thread,
- FACE_getIFCo(f, nextLvl, S, fx - 1, fy - 1),
- FACE_getIFCo(f, nextLvl, S, fx + 1, fy - 1),
- FACE_getIFCo(f, nextLvl, S, fx + 1, fy + 1),
- FACE_getIFCo(f, nextLvl, S, fx - 1, fy + 1),
- ss);
-
- VertDataAvg4(r_thread,
- FACE_getIFCo(f, nextLvl, S, fx - 1, fy + 0),
- FACE_getIFCo(f, nextLvl, S, fx + 1, fy + 0),
- FACE_getIFCo(f, nextLvl, S, fx + 0, fy - 1),
- FACE_getIFCo(f, nextLvl, S, fx + 0, fy + 1),
- ss);
-
- VertDataCopy(nCo, co, ss);
- VertDataSub(nCo, q_thread, ss);
- VertDataMulN(nCo, 0.25f, ss);
- VertDataAdd(nCo, r_thread, ss);
- }
- }
-
- /* interior edge interior shift
- * - old interior edge point (shifting)
- * - new interior edge midpoints
- * - new interior face midpoints
- */
- for (x = 1; x < gridSize - 1; x++) {
- int fx = x * 2;
- const float *co = FACE_getIECo(f, curLvl, S, x);
- float *nCo = FACE_getIECo(f, nextLvl, S, fx);
-
- VertDataAvg4(q_thread,
- FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx - 1),
- FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx + 1),
- FACE_getIFCo(f, nextLvl, S, fx + 1, +1),
- FACE_getIFCo(f, nextLvl, S, fx - 1, +1), ss);
-
- VertDataAvg4(r_thread,
- FACE_getIECo(f, nextLvl, S, fx - 1),
- FACE_getIECo(f, nextLvl, S, fx + 1),
- FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx),
- FACE_getIFCo(f, nextLvl, S, fx, 1),
- ss);
-
- VertDataCopy(nCo, co, ss);
- VertDataSub(nCo, q_thread, ss);
- VertDataMulN(nCo, 0.25f, ss);
- VertDataAdd(nCo, r_thread, ss);
- }
- }
- }
-
-#pragma omp critical
- {
- MEM_freeN(q_thread);
- MEM_freeN(r_thread);
- }
- }
+ BLI_task_parallel_range(0, numEffectedF,
+ &data,
+ ccgSubSurf__calcSubdivLevel_interior_faces_edges_centerpoints_shift_cb,
+ numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT);
/* copy down */
edgeSize = ccg_edgesize(nextLvl);
- gridSize = ccg_gridsize(nextLvl);
- const int cornerIdx = gridSize - 1;
-#pragma omp parallel for private(i) if (numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT)
+ /* Not worth parallelizing. */
for (i = 0; i < numEffectedE; i++) {
CCGEdge *e = effectedE[i];
VertDataCopy(EDGE_getCo(e, nextLvl, 0), VERT_getCo(e->v0, nextLvl), ss);
VertDataCopy(EDGE_getCo(e, nextLvl, edgeSize - 1), VERT_getCo(e->v1, nextLvl), ss);
}
-#pragma omp parallel for private(i) if (numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT)
- for (i = 0; i < numEffectedF; i++) {
- CCGFace *f = effectedF[i];
- int S, x;
-
- for (S = 0; S < f->numVerts; S++) {
- CCGEdge *e = FACE_getEdges(f)[S];
- CCGEdge *prevE = FACE_getEdges(f)[(S + f->numVerts - 1) % f->numVerts];
-
- VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), (float *)FACE_getCenterData(f), ss);
- VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), (float *)FACE_getCenterData(f), ss);
- VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], nextLvl), ss);
- VertDataCopy(FACE_getIECo(f, nextLvl, S, cornerIdx), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, cornerIdx), ss);
- for (x = 1; x < gridSize - 1; x++) {
- float *co = FACE_getIECo(f, nextLvl, S, x);
- VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, 0), co, ss);
- VertDataCopy(FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 0, x), co, ss);
- }
- for (x = 0; x < gridSize - 1; x++) {
- int eI = gridSize - 1 - x;
- VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, x), _edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, eI, vertDataSize), ss);
- VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, eI, vertDataSize), ss);
- }
- }
- }
+ BLI_task_parallel_range(0, numEffectedF,
+ &data,
+ ccgSubSurf__calcSubdivLevel_verts_copydata_cb,
+ numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT);
}
void ccgSubSurf__sync_legacy(CCGSubSurf *ss)
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 5b7947df9dd..07de2ad6342 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -800,8 +800,7 @@ static void nlastrips_path_rename_fix(ID *owner_id, const char *prefix, const ch
}
}
-/* ----------------------- */
-
+/* Rename Sub-ID Entities in RNA Paths ----------------------- */
/* Fix up the given RNA-Path
*
@@ -947,8 +946,7 @@ void BKE_animdata_fix_paths_rename(ID *owner_id, AnimData *adt, ID *ref_id, cons
MEM_freeN(newN);
}
-/* *************************** */
-/* remove of individual paths */
+/* Remove FCurves with Prefix -------------------------------------- */
/* Check RNA-Paths for a list of F-Curves */
static void fcurves_path_remove_fix(const char *prefix, ListBase *curves)
@@ -976,7 +974,6 @@ static void nlastrips_path_remove_fix(const char *prefix, ListBase *strips)
/* recursively check strips, fixing only actions... */
for (strip = strips->first; strip; strip = strip->next) {
-
/* fix strip's action */
if (strip->act)
fcurves_path_remove_fix(prefix, &strip->act->curves);
@@ -999,7 +996,6 @@ void BKE_animdata_fix_paths_remove(ID *id, const char *prefix)
/* check if there's any AnimData to start with */
if (adt) {
-
/* free fcurves */
if (adt->action)
fcurves_path_remove_fix(prefix, &adt->action->curves);
@@ -1017,6 +1013,75 @@ void BKE_animdata_fix_paths_remove(ID *id, const char *prefix)
}
}
+
+/* Apply Op to All FCurves in Database --------------------------- */
+
+/* "User-Data" wrapper used by BKE_fcurves_main_cb() */
+typedef struct AllFCurvesCbWrapper {
+ ID_FCurve_Edit_Callback func; /* Operation to apply on F-Curve */
+ void *user_data; /* Custom data for that operation */
+} AllFCurvesCbWrapper;
+
+/* Helper for adt_apply_all_fcurves_cb() - Apply wrapped operator to list of F-Curves */
+static void fcurves_apply_cb(ID *id, ListBase *fcurves, ID_FCurve_Edit_Callback func, void *user_data)
+{
+ FCurve *fcu;
+
+ for (fcu = fcurves->first; fcu; fcu = fcu->next) {
+ func(id, fcu, user_data);
+ }
+}
+
+/* Helper for adt_apply_all_fcurves_cb() - Recursively go through each NLA strip */
+static void nlastrips_apply_all_curves_cb(ID *id, ListBase *strips, AllFCurvesCbWrapper *wrapper)
+{
+ NlaStrip *strip;
+
+ for (strip = strips->first; strip; strip = strip->next) {
+ /* fix strip's action */
+ if (strip->act) {
+ fcurves_apply_cb(id, &strip->act->curves, wrapper->func, wrapper->user_data);
+ }
+
+ /* check sub-strips (if metas) */
+ nlastrips_apply_all_curves_cb(id, &strip->strips, wrapper);
+ }
+}
+
+/* Helper for BKE_fcurves_main_cb() - Dispatch wrapped operator to all F-Curves */
+static void adt_apply_all_fcurves_cb(ID *id, AnimData *adt, void *wrapper_data)
+{
+ AllFCurvesCbWrapper *wrapper = wrapper_data;
+ NlaTrack *nlt;
+
+ if (adt->action) {
+ fcurves_apply_cb(id, &adt->action->curves, wrapper->func, wrapper->user_data);
+ }
+
+ if (adt->tmpact) {
+ fcurves_apply_cb(id, &adt->tmpact->curves, wrapper->func, wrapper->user_data);
+ }
+
+ /* free drivers - stored as a list of F-Curves */
+ fcurves_apply_cb(id, &adt->drivers, wrapper->func, wrapper->user_data);
+
+ /* NLA Data - Animation Data for Strips */
+ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ nlastrips_apply_all_curves_cb(id, &nlt->strips, wrapper);
+ }
+}
+
+/* apply the given callback function on all F-Curves attached to data in main database */
+void BKE_fcurves_main_cb(Main *mainptr, ID_FCurve_Edit_Callback func, void *user_data)
+{
+ /* Wrap F-Curve operation stuff to pass to the general AnimData-level func */
+ AllFCurvesCbWrapper wrapper = {func, user_data};
+
+ /* Use the AnimData-based function so that we don't have to reimplement all that stuff */
+ BKE_animdata_main_cb(mainptr, adt_apply_all_fcurves_cb, &wrapper);
+}
+
+
/* Whole Database Ops -------------------------------------------- */
/* apply the given callback function on all data in main database */
diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c
index 155967c7bd2..1b8bf3feb10 100644
--- a/source/blender/blenkernel/intern/armature_update.c
+++ b/source/blender/blenkernel/intern/armature_update.c
@@ -700,8 +700,6 @@ void BKE_pose_eval_flush(const struct EvaluationContext *UNUSED(eval_ctx),
/* 6. release the IK tree */
BIK_release_tree(scene, ob, ctime);
-
- ob->recalc &= ~OB_RECALC_ALL;
}
void BKE_pose_eval_proxy_copy(const struct EvaluationContext *UNUSED(eval_ctx), Object *ob)
@@ -712,8 +710,4 @@ void BKE_pose_eval_proxy_copy(const struct EvaluationContext *UNUSED(eval_ctx),
printf("Proxy copy error, lib Object: %s proxy Object: %s\n",
ob->id.name + 2, ob->proxy_from->id.name + 2);
}
- /* Rest of operations are NO-OP in depsgraph, so can clear
- * flag now.
- */
- ob->recalc &= ~OB_RECALC_ALL;
}
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index 25305b1d25a..8d69563f5ff 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -34,12 +34,14 @@
#include "BLI_string_utils.h"
#include "BKE_collection.h"
+#include "BKE_group.h"
#include "BKE_idprop.h"
#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_scene.h"
+#include "DNA_group_types.h"
#include "DNA_ID.h"
#include "DNA_layer_types.h"
#include "DNA_object_types.h"
@@ -47,15 +49,31 @@
#include "MEM_guardedalloc.h"
+/* Prototypes. */
+static bool is_collection_in_tree(const struct SceneCollection *sc_reference, struct SceneCollection *sc_parent);
+
+static SceneCollection *collection_master_from_id(const ID *owner_id)
+{
+ switch (GS(owner_id->name)) {
+ case ID_SCE:
+ return ((Scene *)owner_id)->collection;
+ case ID_GR:
+ return ((Group *)owner_id)->collection;
+ default:
+ BLI_assert(!"ID doesn't support collections");
+ return NULL;
+ }
+}
/**
* Add a collection to a collection ListBase and syncronize all render layers
* The ListBase is NULL when the collection is to be added to the master collection
*/
-SceneCollection *BKE_collection_add(Scene *scene, SceneCollection *sc_parent, const char *name)
+SceneCollection *BKE_collection_add(ID *owner_id, SceneCollection *sc_parent, const int type, const char *name)
{
- SceneCollection *sc_master = BKE_collection_master(scene);
+ SceneCollection *sc_master = collection_master_from_id(owner_id);
SceneCollection *sc = MEM_callocN(sizeof(SceneCollection), "New Collection");
+ sc->type = type;
if (!name) {
name = DATA_("New Collection");
@@ -65,10 +83,10 @@ SceneCollection *BKE_collection_add(Scene *scene, SceneCollection *sc_parent, co
sc_parent = sc_master;
}
- BKE_collection_rename(scene, sc, name);
+ BKE_collection_rename((Scene *)owner_id, sc, name);
BLI_addtail(&sc_parent->scene_collections, sc);
- BKE_layer_sync_new_scene_collection(scene, sc_parent, sc);
+ BKE_layer_sync_new_scene_collection(owner_id, sc_parent, sc);
return sc;
}
@@ -147,25 +165,25 @@ static void layer_collection_remove(ViewLayer *view_layer, ListBase *lb, const S
/**
* Remove a collection from the scene, and syncronize all render layers
*/
-bool BKE_collection_remove(Scene *scene, SceneCollection *sc)
+bool BKE_collection_remove(ID *owner_id, SceneCollection *sc)
{
- SceneCollection *sc_master = BKE_collection_master(scene);
+ SceneCollection *sc_master = collection_master_from_id(owner_id);
- /* the master collection cannot be removed */
+ /* The master collection cannot be removed. */
if (sc == sc_master) {
return false;
}
- /* unlink from the respective collection tree */
+ /* Unlink from the respective collection tree. */
if (!collection_remlink(sc_master, sc)) {
BLI_assert(false);
}
- /* clear the collection items */
+ /* Clear the collection items. */
collection_free(sc, true);
/* check all layers that use this collection and clear them */
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ for (ViewLayer *view_layer = BKE_view_layer_first_from_id(owner_id); view_layer; view_layer = view_layer->next) {
layer_collection_remove(view_layer, &view_layer->layer_collections, sc);
view_layer->active_collection = 0;
}
@@ -175,11 +193,54 @@ bool BKE_collection_remove(Scene *scene, SceneCollection *sc)
}
/**
- * Returns the master collection
+ * Copy SceneCollection tree but keep pointing to the same objects
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
*/
-SceneCollection *BKE_collection_master(const Scene *scene)
+void BKE_collection_copy_data(SceneCollection *sc_dst, SceneCollection *sc_src, const int flag)
+{
+ BLI_duplicatelist(&sc_dst->objects, &sc_src->objects);
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ for (LinkData *link = sc_dst->objects.first; link; link = link->next) {
+ id_us_plus(link->data);
+ }
+ }
+
+ BLI_duplicatelist(&sc_dst->filter_objects, &sc_src->filter_objects);
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ for (LinkData *link = sc_dst->filter_objects.first; link; link = link->next) {
+ id_us_plus(link->data);
+ }
+ }
+
+ BLI_duplicatelist(&sc_dst->scene_collections, &sc_src->scene_collections);
+ for (SceneCollection *nsc_src = sc_src->scene_collections.first, *nsc_dst = sc_dst->scene_collections.first;
+ nsc_src;
+ nsc_src = nsc_src->next, nsc_dst = nsc_dst->next)
+ {
+ BKE_collection_copy_data(nsc_dst, nsc_src, flag);
+ }
+}
+
+static SceneCollection *master_collection_from_id(const ID *owner_id)
{
- return scene->collection;
+ switch (GS(owner_id->name)) {
+ case ID_SCE:
+ return ((const Scene *)owner_id)->collection;
+ case ID_GR:
+ return ((const Group *)owner_id)->collection;
+ default:
+ BLI_assert(!"ID doesn't support scene collection");
+ return NULL;
+ }
+}
+
+/**
+ * Returns the master collection of the scene or group
+ */
+SceneCollection *BKE_collection_master(const ID *owner_id)
+{
+ return master_collection_from_id(owner_id);
}
struct UniqueNameCheckData {
@@ -207,41 +268,58 @@ static bool collection_unique_name_check(void *arg, const char *name)
return false;
}
-void BKE_collection_rename(const Scene *scene, SceneCollection *sc, const char *name)
+static void collection_rename(const ID *owner_id, SceneCollection *sc, const char *name)
{
- SceneCollection *sc_master = BKE_collection_master(scene);
+ SceneCollection *sc_master = collection_master_from_id(owner_id);
struct UniqueNameCheckData data = {.lb = &sc_master->scene_collections, .lookup_sc = sc};
BLI_strncpy(sc->name, name, sizeof(sc->name));
BLI_uniquename_cb(collection_unique_name_check, &data, DATA_("Collection"), '.', sc->name, sizeof(sc->name));
}
+void BKE_collection_rename(const Scene *scene, SceneCollection *sc, const char *name)
+{
+ collection_rename(&scene->id, sc, name);
+}
+
/**
* Free (or release) any data used by the master collection (does not free the master collection itself).
- * Used only to clear the entire scene data since it's not doing re-syncing of the LayerCollection tree
+ * Used only to clear the entire scene or group data since it's not doing re-syncing of the LayerCollection tree
*/
-void BKE_collection_master_free(Scene *scene, const bool do_id_user)
+void BKE_collection_master_free(ID *owner_id, const bool do_id_user)
{
- collection_free(BKE_collection_master(scene), do_id_user);
+ collection_free(BKE_collection_master(owner_id), do_id_user);
}
-static void collection_object_add(const Scene *scene, SceneCollection *sc, Object *ob)
+static void collection_object_add(const ID *owner_id, SceneCollection *sc, Object *ob)
{
BLI_addtail(&sc->objects, BLI_genericNodeN(ob));
- id_us_plus((ID *)ob);
- BKE_layer_sync_object_link(scene, sc, ob);
+
+ if (GS(owner_id->name) == ID_SCE) {
+ id_us_plus((ID *)ob);
+ }
+ else {
+ BLI_assert(GS(owner_id->name) == ID_GR);
+ if ((ob->flag & OB_FROMGROUP) == 0) {
+ ob->flag |= OB_FROMGROUP;
+ }
+ }
+
+ BKE_layer_sync_object_link(owner_id, sc, ob);
}
/**
* Add object to collection
*/
-void BKE_collection_object_add(const Scene *scene, SceneCollection *sc, Object *ob)
+bool BKE_collection_object_add(const ID *owner_id, SceneCollection *sc, Object *ob)
{
if (BLI_findptr(&sc->objects, ob, offsetof(LinkData, data))) {
/* don't add the same object twice */
- return;
+ return false;
}
- collection_object_add(scene, sc, ob);
+
+ collection_object_add(owner_id, sc, ob);
+ return true;
}
/**
@@ -253,7 +331,7 @@ void BKE_collection_object_add_from(Scene *scene, Object *ob_src, Object *ob_dst
FOREACH_SCENE_COLLECTION(scene, sc)
{
if (BLI_findptr(&sc->objects, ob_src, offsetof(LinkData, data))) {
- collection_object_add(scene, sc, ob_dst);
+ collection_object_add(&scene->id, sc, ob_dst);
}
}
FOREACH_SCENE_COLLECTION_END
@@ -274,50 +352,139 @@ void BKE_collection_object_add_from(Scene *scene, Object *ob_src, Object *ob_dst
* Remove object from collection.
* \param bmain: Can be NULL if free_us is false.
*/
-void BKE_collection_object_remove(Main *bmain, const Scene *scene, SceneCollection *sc, Object *ob, const bool free_us)
+bool BKE_collection_object_remove(Main *bmain, ID *owner_id, SceneCollection *sc, Object *ob, const bool free_us)
{
-
LinkData *link = BLI_findptr(&sc->objects, ob, offsetof(LinkData, data));
if (link == NULL) {
- return;
+ return false;
}
BLI_remlink(&sc->objects, link);
MEM_freeN(link);
TODO_LAYER_SYNC_FILTER; /* need to remove all instances of ob in scene collections -> filter_objects */
- BKE_layer_sync_object_unlink(scene, sc, ob);
+ BKE_layer_sync_object_unlink(owner_id, sc, ob);
- if (free_us) {
- BKE_libblock_free_us(bmain, ob);
+ if (GS(owner_id->name) == ID_SCE) {
+ if (free_us) {
+ BKE_libblock_free_us(bmain, ob);
+ }
+ else {
+ id_us_min(&ob->id);
+ }
}
else {
- id_us_min(&ob->id);
+ BLI_assert(GS(owner_id->name) == ID_GR);
}
+
+ return true;
}
/**
* Move object from a collection into another
*/
-void BKE_collection_object_move(const Scene *scene, SceneCollection *sc_dst, SceneCollection *sc_src, Object *ob)
+void BKE_collection_object_move(ID *owner_id, SceneCollection *sc_dst, SceneCollection *sc_src, Object *ob)
{
- BKE_collection_object_add(scene, sc_dst, ob);
- BKE_collection_object_remove(NULL, scene, sc_src, ob, false);
+ BKE_collection_object_add(owner_id, sc_dst, ob);
+ BKE_collection_object_remove(NULL, owner_id, sc_src, ob, false);
}
/**
* Remove object from all collections of scene
*/
-void BKE_collections_object_remove(Main *bmain, Scene *scene, Object *ob, const bool free_us)
+bool BKE_collections_object_remove(Main *bmain, ID *owner_id, Object *ob, const bool free_us)
{
- BKE_scene_remove_rigidbody_object(scene, ob);
+ bool removed = false;
+ if (GS(owner_id->name) == ID_SCE) {
+ BKE_scene_remove_rigidbody_object((Scene *)owner_id, ob);
+ }
+ else {
+ BLI_assert(GS(owner_id->name) == ID_GR);
+ }
- FOREACH_SCENE_COLLECTION(scene, sc)
+ FOREACH_SCENE_COLLECTION(owner_id, sc)
{
- BKE_collection_object_remove(bmain, scene, sc, ob, free_us);
+ removed |= BKE_collection_object_remove(bmain, owner_id, sc, ob, free_us);
}
FOREACH_SCENE_COLLECTION_END
+ return removed;
+}
+
+static void layer_collection_sync(LayerCollection *lc_dst, LayerCollection *lc_src)
+{
+ lc_dst->flag = lc_src->flag;
+
+ /* Pending: sync overrides. */
+ IDP_MergeGroup(lc_dst->properties, lc_src->properties, true);
+
+ /* Continue recursively. */
+ LayerCollection *lc_dst_nested, *lc_src_nested;
+ lc_src_nested = lc_src->layer_collections.first;
+ for (lc_dst_nested = lc_dst->layer_collections.first;
+ lc_dst_nested && lc_src_nested;
+ lc_dst_nested = lc_dst_nested->next, lc_src_nested = lc_src_nested->next)
+ {
+ layer_collection_sync(lc_dst_nested, lc_src_nested);
+ }
+}
+
+/**
+ * Leave only the master collection in, remove everything else.
+ * @param group
+ */
+static void collection_group_cleanup(Group *group)
+{
+ /* Unlink all the LayerCollections. */
+ while (group->view_layer->layer_collections.last != NULL) {
+ BKE_collection_unlink(group->view_layer, group->view_layer->layer_collections.last);
+ }
+
+ /* Remove all the SceneCollections but the master. */
+ collection_free(group->collection, false);
+}
+
+/**
+ * Create a group from a collection
+ *
+ * Any ViewLayer that may have this the related SceneCollection linked is converted
+ * to a Group Collection.
+ */
+Group *BKE_collection_group_create(Main *bmain, Scene *scene, LayerCollection *lc_src)
+{
+ SceneCollection *sc_dst, *sc_src = lc_src->scene_collection;
+ LayerCollection *lc_dst;
+
+ /* The master collection can't be converted. */
+ if (sc_src == BKE_collection_master(&scene->id)) {
+ return NULL;
+ }
+
+ /* If a sub-collection of sc_dst is directly linked into a ViewLayer we can't convert. */
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ for (LayerCollection *lc_child = view_layer->layer_collections.first; lc_child; lc_child = lc_child->next) {
+ if (is_collection_in_tree(lc_child->scene_collection, sc_src)) {
+ return NULL;
+ }
+ }
+ }
+
+ /* Create new group with the same data as the original collection. */
+ Group *group = BKE_group_add(bmain, sc_src->name);
+ collection_group_cleanup(group);
+
+ sc_dst = BKE_collection_add(&group->id, NULL, COLLECTION_TYPE_GROUP_INTERNAL, sc_src->name);
+ BKE_collection_copy_data(sc_dst, sc_src, 0);
+ FOREACH_SCENE_COLLECTION(&group->id, sc_group)
+ {
+ sc_group->type = COLLECTION_TYPE_GROUP_INTERNAL;
+ }
+ FOREACH_SCENE_COLLECTION_END
+
+ lc_dst = BKE_collection_link(group->view_layer, sc_dst);
+ layer_collection_sync(lc_dst, lc_src);
+
+ return group;
}
/* ---------------------------------------------------------------------- */
@@ -353,10 +520,10 @@ static bool is_collection_in_tree(const SceneCollection *sc_reference, SceneColl
return find_collection_parent(sc_reference, sc_parent) != NULL;
}
-bool BKE_collection_move_above(const Scene *scene, SceneCollection *sc_dst, SceneCollection *sc_src)
+bool BKE_collection_move_above(const ID *owner_id, SceneCollection *sc_dst, SceneCollection *sc_src)
{
/* Find the SceneCollection the sc_src belongs to */
- SceneCollection *sc_master = BKE_collection_master(scene);
+ SceneCollection *sc_master = master_collection_from_id(owner_id);
/* Master Layer can't be moved around*/
if (ELEM(sc_master, sc_src, sc_dst)) {
@@ -386,16 +553,16 @@ bool BKE_collection_move_above(const Scene *scene, SceneCollection *sc_dst, Scen
BLI_insertlinkbefore(&sc_dst_parent->scene_collections, sc_dst, sc_src);
/* Update the tree */
- BKE_layer_collection_resync(scene, sc_src_parent);
- BKE_layer_collection_resync(scene, sc_dst_parent);
+ BKE_layer_collection_resync(owner_id, sc_src_parent);
+ BKE_layer_collection_resync(owner_id, sc_dst_parent);
return true;
}
-bool BKE_collection_move_below(const Scene *scene, SceneCollection *sc_dst, SceneCollection *sc_src)
+bool BKE_collection_move_below(const ID *owner_id, SceneCollection *sc_dst, SceneCollection *sc_src)
{
/* Find the SceneCollection the sc_src belongs to */
- SceneCollection *sc_master = BKE_collection_master(scene);
+ SceneCollection *sc_master = master_collection_from_id(owner_id);
/* Master Layer can't be moved around*/
if (ELEM(sc_master, sc_src, sc_dst)) {
@@ -425,16 +592,16 @@ bool BKE_collection_move_below(const Scene *scene, SceneCollection *sc_dst, Scen
BLI_insertlinkafter(&sc_dst_parent->scene_collections, sc_dst, sc_src);
/* Update the tree */
- BKE_layer_collection_resync(scene, sc_src_parent);
- BKE_layer_collection_resync(scene, sc_dst_parent);
+ BKE_layer_collection_resync(owner_id, sc_src_parent);
+ BKE_layer_collection_resync(owner_id, sc_dst_parent);
return true;
}
-bool BKE_collection_move_into(const Scene *scene, SceneCollection *sc_dst, SceneCollection *sc_src)
+bool BKE_collection_move_into(const ID *owner_id, SceneCollection *sc_dst, SceneCollection *sc_src)
{
/* Find the SceneCollection the sc_src belongs to */
- SceneCollection *sc_master = BKE_collection_master(scene);
+ SceneCollection *sc_master = master_collection_from_id(owner_id);
if (sc_src == sc_master) {
return false;
}
@@ -460,8 +627,8 @@ bool BKE_collection_move_into(const Scene *scene, SceneCollection *sc_dst, Scene
BLI_addtail(&sc_dst->scene_collections, sc_src);
/* Update the tree */
- BKE_layer_collection_resync(scene, sc_src_parent);
- BKE_layer_collection_resync(scene, sc_dst);
+ BKE_layer_collection_resync(owner_id, sc_src_parent);
+ BKE_layer_collection_resync(owner_id, sc_dst);
return true;
}
@@ -471,7 +638,7 @@ bool BKE_collection_move_into(const Scene *scene, SceneCollection *sc_dst, Scene
/* scene collection iteractor */
typedef struct SceneCollectionsIteratorData {
- Scene *scene;
+ ID *owner_id;
void **array;
int tot, cur;
} SceneCollectionsIteratorData;
@@ -498,17 +665,20 @@ static void scene_collections_build_array(SceneCollection *sc, void *data)
(*array)++;
}
-static void scene_collections_array(Scene *scene, SceneCollection ***collections_array, int *tot)
+static void scene_collections_array(ID *owner_id, SceneCollection ***collections_array, int *tot)
{
- SceneCollection *sc = BKE_collection_master(scene);
+ SceneCollection *sc;
SceneCollection **array;
*collections_array = NULL;
*tot = 0;
- if (scene == NULL)
+ if (owner_id == NULL) {
return;
+ }
+ sc = master_collection_from_id(owner_id);
+ BLI_assert(sc != NULL);
scene_collection_callback(sc, scene_collections_count, tot);
if (*tot == 0)
@@ -524,13 +694,13 @@ static void scene_collections_array(Scene *scene, SceneCollection ***collections
*/
void BKE_scene_collections_iterator_begin(BLI_Iterator *iter, void *data_in)
{
- Scene *scene = data_in;
+ ID *owner_id = data_in;
SceneCollectionsIteratorData *data = MEM_callocN(sizeof(SceneCollectionsIteratorData), __func__);
- data->scene = scene;
+ data->owner_id = owner_id;
iter->data = data;
- scene_collections_array(scene, (SceneCollection ***)&data->array, &data->tot);
+ scene_collections_array(owner_id, (SceneCollection ***)&data->array, &data->tot);
BLI_assert(data->tot != 0);
data->cur = 0;
diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c
index a004d32847a..2f80fbbec46 100644
--- a/source/blender/blenkernel/intern/collision.c
+++ b/source/blender/blenkernel/intern/collision.c
@@ -47,6 +47,7 @@
#include "BKE_cloth.h"
#include "BKE_effect.h"
+#include "BKE_group.h"
#include "BKE_layer.h"
#include "BKE_modifier.h"
#include "BKE_scene.h"
@@ -502,12 +503,14 @@ static void add_collision_object(Object ***objs, unsigned int *numobj, unsigned
/* objects in dupli groups, one level only for now */
if (ob->dup_group && level == 0) {
- GroupObject *go;
Group *group= ob->dup_group;
/* add objects */
- for (go= group->gobject.first; go; go= go->next)
- add_collision_object(objs, numobj, maxobj, go->ob, self, level+1, modifier_type);
+ FOREACH_GROUP_OBJECT(group, object)
+ {
+ add_collision_object(objs, numobj, maxobj, object, self, level+1, modifier_type);
+ }
+ FOREACH_GROUP_OBJECT_END
}
}
@@ -515,9 +518,7 @@ static void add_collision_object(Object ***objs, unsigned int *numobj, unsigned
// collision object will exclude self
Object **get_collisionobjects_ext(Scene *scene, Object *self, Group *group, unsigned int *numcollobj, unsigned int modifier_type, bool dupli)
{
- Base *base;
Object **objs;
- GroupObject *go;
unsigned int numobj= 0, maxobj= 100;
int level = dupli ? 0 : 1;
@@ -526,11 +527,15 @@ Object **get_collisionobjects_ext(Scene *scene, Object *self, Group *group, unsi
/* gather all collision objects */
if (group) {
/* use specified group */
- for (go= group->gobject.first; go; go= go->next)
- add_collision_object(&objs, &numobj, &maxobj, go->ob, self, level, modifier_type);
+ FOREACH_GROUP_OBJECT(group, object)
+ {
+ add_collision_object(&objs, &numobj, &maxobj, object, self, level, modifier_type);
+ }
+ FOREACH_GROUP_OBJECT_END
}
else {
Scene *sce_iter;
+ Base *base;
/* add objects in same layer in scene */
for (SETLOOPER(scene, sce_iter, base)) {
if ((base->flag & BASE_VISIBLED) != 0) {
@@ -576,24 +581,28 @@ static void add_collider_cache_object(ListBase **objs, Object *ob, Object *self,
/* objects in dupli groups, one level only for now */
if (ob->dup_group && level == 0) {
- GroupObject *go;
Group *group= ob->dup_group;
/* add objects */
- for (go= group->gobject.first; go; go= go->next)
- add_collider_cache_object(objs, go->ob, self, level+1);
+ FOREACH_GROUP_OBJECT(group, object)
+ {
+ add_collider_cache_object(objs, object, self, level+1);
+ }
+ FOREACH_GROUP_OBJECT_END
}
}
ListBase *get_collider_cache(Scene *scene, Object *self, Group *group)
{
- GroupObject *go;
ListBase *objs= NULL;
/* add object in same layer in scene */
if (group) {
- for (go= group->gobject.first; go; go= go->next)
- add_collider_cache_object(&objs, go->ob, self, 0);
+ FOREACH_GROUP_OBJECT(group, object)
+ {
+ add_collider_cache_object(&objs, object, self, 0);
+ }
+ FOREACH_GROUP_OBJECT_END
}
else {
Scene *sce_iter;
@@ -802,8 +811,8 @@ int cloth_bvh_objcollision(Object *ob, ClothModifierData *clmd, float step, floa
if ( cloth->bvhselftree ) {
// search for overlapping collision pairs
overlap = BLI_bvhtree_overlap(cloth->bvhselftree, cloth->bvhselftree, &result, NULL, NULL);
-
- // #pragma omp parallel for private(k, i, j) schedule(static)
+
+ /* Could be parallelized (using BLI_task)... */
for ( k = 0; k < result; k++ ) {
float temp[3];
float length = 0;
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index 8067c1edce0..1f673d2c15f 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -679,6 +679,11 @@ struct wmManipulatorGroup *CTX_wm_manipulator_group(const bContext *C)
return C->wm.manipulator_group;
}
+struct wmMsgBus *CTX_wm_message_bus(const bContext *C)
+{
+ return C->wm.manager ? C->wm.manager->message_bus : NULL;
+}
+
struct ReportList *CTX_wm_reports(const bContext *C)
{
if (C->wm.manager)
@@ -955,7 +960,7 @@ ViewRender *CTX_data_view_render(const bContext *C)
}
}
-RenderEngineType *CTX_data_engine(const bContext *C)
+RenderEngineType *CTX_data_engine_type(const bContext *C)
{
ViewRender *view_render = CTX_data_view_render(C);
return RE_engines_find(view_render->engine_id);
@@ -999,7 +1004,7 @@ SceneCollection *CTX_data_scene_collection(const bContext *C)
/* fallback */
Scene *scene = CTX_data_scene(C);
- return BKE_collection_master(scene);
+ return BKE_collection_master(&scene->id);
}
int CTX_data_mode_enum_ex(const Object *obedit, const Object *ob)
@@ -1277,8 +1282,8 @@ void CTX_data_eval_ctx(const bContext *C, EvaluationContext *eval_ctx)
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- RenderEngineType *engine = CTX_data_engine(C);
+ RenderEngineType *engine_type = CTX_data_engine_type(C);
DEG_evaluation_context_init_from_scene(eval_ctx,
- scene, view_layer, engine,
+ scene, view_layer, engine_type,
DAG_EVAL_VIEWPORT);
}
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 9e292422019..80a31697424 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -491,33 +491,24 @@ static void scene_setSubframe(Scene *scene, float subframe)
static int surface_getBrushFlags(DynamicPaintSurface *surface, const ViewLayer *view_layer)
{
Base *base = NULL;
- GroupObject *go = NULL;
Object *brushObj = NULL;
ModifierData *md = NULL;
int flags = 0;
if (surface->brush_group)
- go = surface->brush_group->gobject.first;
+ base = FIRSTBASE(surface->brush_group->view_layer);
else
base = FIRSTBASE(view_layer);
- while (base || go) {
+ while (base) {
brushObj = NULL;
/* select object */
- if (surface->brush_group) {
- if (go->ob)
- brushObj = go->ob;
- }
- else {
- brushObj = base->object;
- }
+ brushObj = base->object;
- if (surface->brush_group)
- go = go->next;
- else
- base = base->next;
+ /* next item */
+ base = base->next;
if (!brushObj) {
continue;
@@ -5780,7 +5771,6 @@ static int dynamicPaint_doStep(const struct EvaluationContext *eval_ctx, Scene *
*/
{
Base *base = NULL;
- GroupObject *go = NULL;
Object *brushObj = NULL;
ModifierData *md = NULL;
ViewLayer *view_layer = eval_ctx->view_layer;
@@ -5791,25 +5781,17 @@ static int dynamicPaint_doStep(const struct EvaluationContext *eval_ctx, Scene *
/* either from group or from all objects */
if (surface->brush_group)
- go = surface->brush_group->gobject.first;
+ base = FIRSTBASE(surface->brush_group->view_layer);
else
base = FIRSTBASE(view_layer);
- while (base || go) {
+ while (base) {
brushObj = NULL;
/* select object */
- if (surface->brush_group) {
- if (go->ob)
- brushObj = go->ob;
- }
- else
- brushObj = base->object;
+ brushObj = base->object;
/* next item */
- if (surface->brush_group)
- go = go->next;
- else
- base = base->next;
+ base = base->next;
if (!brushObj) {
/* skip item */
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index 502ad9c44a7..16124fb4777 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -64,6 +64,7 @@
#include "BKE_cdderivedmesh.h"
#include "BKE_effect.h"
#include "BKE_global.h"
+#include "BKE_group.h"
#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_modifier.h"
@@ -215,51 +216,41 @@ ListBase *pdInitEffectors(
{
ViewLayer *view_layer;
Base *base;
- unsigned int layer= ob_src->lay;
ListBase *effectors = NULL;
- /* eval_ctx is NULL during deg build */
- if (eval_ctx) {
+ if (weights->group) {
+ view_layer = weights->group->view_layer;
+ }
+ else if (eval_ctx) {
view_layer = eval_ctx->view_layer;
}
else {
+ /* eval_ctx is NULL during deg build */
view_layer = BKE_view_layer_context_active_PLACEHOLDER(scene);
}
-
- if (weights->group) {
- GroupObject *go;
-
- for (go= weights->group->gobject.first; go; go= go->next) {
- if ( (go->ob->lay & layer) ) {
- if ( go->ob->pd && go->ob->pd->forcefield )
- add_object_to_effectors(&effectors, eval_ctx, scene, weights, go->ob, ob_src, for_simulation);
- if ( go->ob->particlesystem.first ) {
- ParticleSystem *psys= go->ob->particlesystem.first;
+ for (base = FIRSTBASE(view_layer); base; base = base->next) {
+ if ((base->flag & BASE_VISIBLED) == 0) {
+ continue;
+ }
- for ( ; psys; psys=psys->next )
- add_particles_to_effectors(&effectors, eval_ctx, scene, weights, go->ob, psys, psys_src, for_simulation);
- }
- }
+ if (base->object->pd && base->object->pd->forcefield) {
+ add_object_to_effectors(&effectors, eval_ctx, scene, weights, base->object, ob_src, for_simulation);
}
- }
- else {
- for (base = FIRSTBASE(view_layer); base; base = base->next) {
- if ( base->object->pd && base->object->pd->forcefield )
- add_object_to_effectors(&effectors, eval_ctx, scene, weights, base->object, ob_src, for_simulation);
- if ( base->object->particlesystem.first ) {
- ParticleSystem *psys= base->object->particlesystem.first;
+ if (base->object->particlesystem.first) {
+ ParticleSystem *psys= base->object->particlesystem.first;
- for ( ; psys; psys=psys->next )
- add_particles_to_effectors(&effectors, eval_ctx, scene, weights, base->object, psys, psys_src, for_simulation);
+ for (; psys; psys=psys->next) {
+ add_particles_to_effectors(&effectors, eval_ctx, scene, weights, base->object, psys, psys_src, for_simulation);
}
}
}
-
- if (for_simulation)
+
+ if (for_simulation) {
pdPrecalculateEffectors(eval_ctx, effectors);
-
+ }
+
return effectors;
}
diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c
index 5e5f8114ead..7c2eefe657c 100644
--- a/source/blender/blenkernel/intern/group.c
+++ b/source/blender/blenkernel/intern/group.c
@@ -45,32 +45,53 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BKE_collection.h"
#include "BKE_global.h"
#include "BKE_group.h"
#include "BKE_icons.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_scene.h"
-static void free_group_object(GroupObject *go)
-{
- MEM_freeN(go);
-}
-
/** Free (or release) any data used by this group (does not free the group itself). */
void BKE_group_free(Group *group)
{
- /* don't free group itself */
- GroupObject *go;
-
/* No animdata here. */
+ BKE_previewimg_free(&group->preview);
- while ((go = BLI_pophead(&group->gobject))) {
- free_group_object(go);
+ if (group->view_layer != NULL) {
+ BKE_view_layer_free(group->view_layer);
+ group->view_layer = NULL;
}
- BKE_previewimg_free(&group->preview);
+ if (group->collection != NULL) {
+ BKE_collection_master_free(&group->id, false);
+ MEM_freeN(group->collection);
+ group->collection = NULL;
+ }
+}
+
+/**
+ * Run when adding new groups or during doversion.
+ */
+void BKE_group_init(Group *group)
+{
+ group->collection = MEM_callocN(sizeof(SceneCollection), __func__);
+ BLI_strncpy(group->collection->name, "Master Collection", sizeof(group->collection->name));
+ group->view_layer = NULL; /* groups are not calloced. */
+ group->view_layer = BKE_view_layer_group_add(group);
+
+ /* Unlink the master collection. */
+ BKE_collection_unlink(group->view_layer, group->view_layer->layer_collections.first);
+
+ /* Create and link a new default collection. */
+ SceneCollection *defaut_collection = BKE_collection_add(&group->id,
+ NULL,
+ COLLECTION_TYPE_GROUP_INTERNAL,
+ "Default Collection");
+ BKE_collection_link(group->view_layer, defaut_collection);
}
Group *BKE_group_add(Main *bmain, const char *name)
@@ -83,7 +104,7 @@ Group *BKE_group_add(Main *bmain, const char *name)
group->layer = (1 << 20) - 1;
group->preview = NULL;
-
+ BKE_group_init(group);
return group;
}
@@ -97,7 +118,8 @@ Group *BKE_group_add(Main *bmain, const char *name)
*/
void BKE_group_copy_data(Main *UNUSED(bmain), Group *group_dst, const Group *group_src, const int flag)
{
- BLI_duplicatelist(&group_dst->gobject, &group_src->gobject);
+ /* We never handle usercount here for own data. */
+ const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
/* Do not copy group's preview (same behavior as for objects). */
if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO temp hack */
@@ -106,6 +128,18 @@ void BKE_group_copy_data(Main *UNUSED(bmain), Group *group_dst, const Group *gro
else {
group_dst->preview = NULL;
}
+
+ group_dst->collection = MEM_dupallocN(group_src->collection);
+ SceneCollection *master_collection_src = BKE_collection_master(&group_src->id);
+ SceneCollection *master_collection_dst = BKE_collection_master(&group_dst->id);
+
+ /* Recursively creates a new SceneCollection tree. */
+ BKE_collection_copy_data(master_collection_dst, master_collection_src,
+ flag_subdata);
+
+ BKE_view_layer_copy_data(group_dst->view_layer, group_src->view_layer,
+ master_collection_dst, master_collection_src,
+ flag_subdata);
}
Group *BKE_group_copy(Main *bmain, const Group *group)
@@ -123,23 +157,19 @@ void BKE_group_make_local(Main *bmain, Group *group, const bool lib_local)
/* external */
static bool group_object_add_internal(Group *group, Object *ob)
{
- GroupObject *go;
-
if (group == NULL || ob == NULL) {
return false;
}
-
- /* check if the object has been added already */
- if (BLI_findptr(&group->gobject, ob, offsetof(GroupObject, ob))) {
+
+ /* For now always add to master collection of the group. */
+ SceneCollection *scene_collection = GROUP_MASTER_COLLECTION(group);
+
+ /* If the object has been added already it returns false. */
+ if (BKE_collection_object_add(&group->id, scene_collection, ob) == false) {
return false;
}
-
- go = MEM_callocN(sizeof(GroupObject), "groupobject");
- BLI_addtail(&group->gobject, go);
-
- go->ob = ob;
- id_us_ensure_real(&go->ob->id);
-
+
+ id_us_ensure_real(&ob->id);
return true;
}
@@ -157,24 +187,17 @@ bool BKE_group_object_add(Group *group, Object *object)
}
/* also used for (ob == NULL) */
-static int group_object_unlink_internal(Group *group, Object *ob)
+static bool group_object_unlink_internal(Group *group, Object *ob)
{
- GroupObject *go, *gon;
- int removed = 0;
- if (group == NULL) return 0;
-
- go = group->gobject.first;
- while (go) {
- gon = go->next;
- if (go->ob == ob) {
- BLI_remlink(&group->gobject, go);
- free_group_object(go);
- removed = 1;
- /* should break here since an object being in a group twice cant happen? */
- }
- go = gon;
+ if (group == NULL) {
+ return false;
+ }
+
+ if (BKE_collections_object_remove(NULL, &group->id, ob, false)) {
+ return true;
}
- return removed;
+
+ return false;
}
static bool group_object_cyclic_check_internal(Object *object, Group *group)
@@ -191,12 +214,13 @@ static bool group_object_cyclic_check_internal(Object *object, Group *group)
if (dup_group == group)
return true;
else {
- GroupObject *gob;
- for (gob = dup_group->gobject.first; gob; gob = gob->next) {
- if (group_object_cyclic_check_internal(gob->ob, group)) {
+ FOREACH_GROUP_OBJECT(dup_group, group_object)
+ {
+ if (group_object_cyclic_check_internal(group_object, dup_group)) {
return true;
}
}
+ FOREACH_GROUP_OBJECT_END
}
/* un-flag the object, it's allowed to have the same group multiple times in parallel */
@@ -234,7 +258,7 @@ bool BKE_group_object_exists(Group *group, Object *ob)
return false;
}
else {
- return (BLI_findptr(&group->gobject, ob, offsetof(GroupObject, ob)) != NULL);
+ return (BLI_findptr(&group->view_layer->object_bases, ob, offsetof(Base, object)));
}
}
@@ -253,31 +277,15 @@ Group *BKE_group_object_find(Group *group, Object *ob)
return NULL;
}
-void BKE_group_tag_recalc(Group *group)
-{
- GroupObject *go;
-
- if (group == NULL) return;
-
- for (go = group->gobject.first; go; go = go->next) {
- if (go->ob)
- go->ob->recalc = go->recalc;
- }
-}
-
bool BKE_group_is_animated(Group *group, Object *UNUSED(parent))
{
- GroupObject *go;
-
-#if 0 /* XXX OLD ANIMSYS, NLASTRIPS ARE NO LONGER USED */
- if (parent->nlastrips.first)
- return 1;
-#endif
-
- for (go = group->gobject.first; go; go = go->next)
- if (go->ob && go->ob->proxy)
+ FOREACH_GROUP_OBJECT(group, object)
+ {
+ if (object->proxy) {
return true;
-
+ }
+ }
+ FOREACH_GROUP_OBJECT_END
return false;
}
@@ -329,8 +337,6 @@ static void group_replaces_nla(Object *parent, Object *target, char mode)
/* note: does not work for derivedmesh and render... it recreates all again in convertblender.c */
void BKE_group_handle_recalc_and_update(const struct EvaluationContext *eval_ctx, Scene *scene, Object *UNUSED(parent), Group *group)
{
- GroupObject *go;
-
#if 0 /* warning, isn't clearing the recalc flag on the object which causes it to run all the time,
* not just on frame change.
* This isn't working because the animation data is only re-evaluated on frame change so commenting for now
@@ -364,12 +370,12 @@ void BKE_group_handle_recalc_and_update(const struct EvaluationContext *eval_ctx
#endif
{
/* only do existing tags, as set by regular depsgraph */
- for (go = group->gobject.first; go; go = go->next) {
- if (go->ob) {
- if (go->ob->recalc) {
- BKE_object_handle_update(eval_ctx, scene, go->ob);
- }
+ FOREACH_GROUP_OBJECT(group, object)
+ {
+ if (object->id.tag & LIB_TAG_ID_RECALC_ALL) {
+ BKE_object_handle_update(eval_ctx, scene, object);
}
}
+ FOREACH_GROUP_OBJECT_END
}
}
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
index 01d8b180344..84eb4ee2e33 100644
--- a/source/blender/blenkernel/intern/layer.c
+++ b/source/blender/blenkernel/intern/layer.c
@@ -35,12 +35,14 @@
#include "BKE_collection.h"
#include "BKE_freestyle.h"
#include "BKE_global.h"
+#include "BKE_group.h"
#include "BKE_idprop.h"
#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_workspace.h"
+#include "DNA_group_types.h"
#include "DNA_ID.h"
#include "DNA_layer_types.h"
#include "DNA_object_types.h"
@@ -89,7 +91,7 @@ ViewLayer *BKE_view_layer_from_workspace_get(const struct Scene *scene, const st
return BKE_view_layer_from_scene_get(scene);
}
else {
- return BKE_workspace_view_layer_get(workspace);
+ return BKE_workspace_view_layer_get(workspace, scene);
}
}
@@ -102,11 +104,7 @@ ViewLayer *BKE_view_layer_context_active_PLACEHOLDER(const Scene *scene)
return BKE_view_layer_from_scene_get(scene);
}
-/**
- * Add a new renderlayer
- * by default, a renderlayer has the master collection
- */
-ViewLayer *BKE_view_layer_add(Scene *scene, const char *name)
+static ViewLayer *view_layer_add(const char *name, SceneCollection *master_scene_collection)
{
if (!name) {
name = DATA_("View Layer");
@@ -118,15 +116,10 @@ ViewLayer *BKE_view_layer_add(Scene *scene, const char *name)
view_layer->properties = IDP_New(IDP_GROUP, &val, ROOT_PROP);
layer_engine_settings_init(view_layer->properties, false);
-
- BLI_addtail(&scene->view_layers, view_layer);
-
- /* unique name */
BLI_strncpy_utf8(view_layer->name, name, sizeof(view_layer->name));
- BLI_uniquename(&scene->view_layers, view_layer, DATA_("ViewLayer"), '.', offsetof(ViewLayer, name), sizeof(view_layer->name));
- SceneCollection *sc = BKE_collection_master(scene);
- layer_collection_add(view_layer, NULL, sc);
+ /* Link the master collection by default. */
+ layer_collection_add(view_layer, NULL, master_scene_collection);
/* Pure rendering pipeline settings. */
view_layer->layflag = 0x7FFF; /* solid ztra halo edge strand */
@@ -138,6 +131,37 @@ ViewLayer *BKE_view_layer_add(Scene *scene, const char *name)
}
/**
+ * Add a new view layer
+ * by default, a view layer has the master collection
+ */
+ViewLayer *BKE_view_layer_add(Scene *scene, const char *name)
+{
+ SceneCollection *sc = BKE_collection_master(&scene->id);
+ ViewLayer *view_layer = view_layer_add(name, sc);
+
+ BLI_addtail(&scene->view_layers, view_layer);
+
+ /* unique name */
+ BLI_uniquename(
+ &scene->view_layers, view_layer, DATA_("ViewLayer"), '.',
+ offsetof(ViewLayer, name), sizeof(view_layer->name));
+
+ return view_layer;
+}
+
+/**
+ * Add a ViewLayer for a Group
+ * It should be added only once
+ */
+ViewLayer *BKE_view_layer_group_add(Group *group)
+{
+ BLI_assert(group->view_layer == NULL);
+ SceneCollection *sc = BKE_collection_master(&group->id);
+ ViewLayer *view_layer = view_layer_add(group->id.name + 2, sc);
+ return view_layer;
+}
+
+/**
* Free (or release) any data used by this ViewLayer.
*/
void BKE_view_layer_free(ViewLayer *view_layer)
@@ -204,6 +228,22 @@ void BKE_view_layer_selected_objects_tag(ViewLayer *view_layer, const int tag)
}
}
+/**
+ * Return the first ViewLayer for a given id
+ */
+ViewLayer *BKE_view_layer_first_from_id(const ID *owner_id)
+{
+ switch (GS(owner_id->name)) {
+ case ID_SCE:
+ return ((Scene *)owner_id)->view_layers.first;
+ case ID_GR:
+ return ((Group *)owner_id)->view_layer;
+ default:
+ BLI_assert(!"ID doesn't support view layers");
+ return NULL;
+ }
+}
+
static bool find_scene_collection_in_scene_collections(ListBase *lb, const LayerCollection *lc)
{
for (LayerCollection *lcn = lb->first; lcn; lcn = lcn->next) {
@@ -238,14 +278,25 @@ Object *BKE_view_layer_camera_find(ViewLayer *view_layer)
/**
* Find the ViewLayer a LayerCollection belongs to
*/
-ViewLayer *BKE_view_layer_find_from_collection(const Scene *scene, LayerCollection *lc)
-{
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
- if (find_scene_collection_in_scene_collections(&view_layer->layer_collections, lc)) {
- return view_layer;
+ViewLayer *BKE_view_layer_find_from_collection(const ID *owner_id, LayerCollection *lc)
+{
+ switch (GS(owner_id->name)) {
+ case ID_GR:
+ return ((Group *)owner_id)->view_layer;
+ case ID_SCE:
+ {
+ Scene *scene = (Scene *)owner_id;
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ if (find_scene_collection_in_scene_collections(&view_layer->layer_collections, lc)) {
+ return view_layer;
+ }
+ }
+ return NULL;
}
+ default:
+ BLI_assert(!"ID doesn't support scene layers");
+ return NULL;
}
- return NULL;
}
/* Base */
@@ -272,6 +323,114 @@ void BKE_view_layer_base_select(struct ViewLayer *view_layer, Base *selbase)
}
}
+/****************************************************************************/
+/* Copying functions for datablocks that use ViewLayer/SceneCollection */
+
+/* Find the equivalent SceneCollection in the new tree */
+static SceneCollection *scene_collection_from_new_tree(
+ SceneCollection *sc_reference, SceneCollection *sc_dst, SceneCollection *sc_src)
+{
+ if (sc_src == sc_reference) {
+ return sc_dst;
+ }
+
+ for (SceneCollection *nsc_src = sc_src->scene_collections.first, *nsc_dst = sc_dst->scene_collections.first;
+ nsc_src;
+ nsc_src = nsc_src->next, nsc_dst = nsc_dst->next)
+ {
+ SceneCollection *found = scene_collection_from_new_tree(sc_reference, nsc_dst, nsc_src);
+ if (found != NULL) {
+ return found;
+ }
+ }
+ return NULL;
+}
+
+static void layer_collections_sync_flags(ListBase *layer_collections_dst, const ListBase *layer_collections_src)
+{
+ LayerCollection *layer_collection_dst = (LayerCollection *)layer_collections_dst->first;
+ const LayerCollection *layer_collection_src = (const LayerCollection *)layer_collections_src->first;
+ while (layer_collection_dst != NULL) {
+ layer_collection_dst->flag = layer_collection_src->flag;
+
+ if (layer_collection_dst->properties != NULL) {
+ IDP_FreeProperty(layer_collection_dst->properties);
+ MEM_SAFE_FREE(layer_collection_dst->properties);
+ }
+
+ if (layer_collection_src->properties != NULL) {
+ layer_collection_dst->properties = IDP_CopyProperty(layer_collection_src->properties);
+ }
+
+ layer_collections_sync_flags(&layer_collection_dst->layer_collections,
+ &layer_collection_src->layer_collections);
+
+ layer_collection_dst = layer_collection_dst->next;
+ layer_collection_src = layer_collection_src->next;
+ }
+}
+
+/* recreate the LayerCollection tree */
+static void layer_collections_recreate(
+ ViewLayer *view_layer_dst, ListBase *lb_src, SceneCollection *mc_dst, SceneCollection *mc_src)
+{
+ for (LayerCollection *lc_src = lb_src->first; lc_src; lc_src = lc_src->next) {
+ SceneCollection *sc_dst = scene_collection_from_new_tree(lc_src->scene_collection, mc_dst, mc_src);
+ BLI_assert(sc_dst);
+
+ /* instead of synchronizing both trees we simply re-create it */
+ BKE_collection_link(view_layer_dst, sc_dst);
+ }
+}
+
+/**
+ * Only copy internal data of ViewLayer from source to already allocated/initialized destination.
+ *
+ * \param mc_src Master Collection the source ViewLayer links in.
+ * \param mc_dst Master Collection the destination ViewLayer links in.
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_view_layer_copy_data(
+ ViewLayer *view_layer_dst, ViewLayer *view_layer_src, SceneCollection *mc_dst, SceneCollection *mc_src,
+ const int flag)
+{
+ IDPropertyTemplate val = {0};
+
+ if (view_layer_dst->id_properties != NULL) {
+ view_layer_dst->id_properties = IDP_CopyProperty_ex(view_layer_dst->id_properties, flag);
+ }
+ BKE_freestyle_config_copy(&view_layer_dst->freestyle_config, &view_layer_src->freestyle_config, flag);
+
+ view_layer_dst->stats = NULL;
+ view_layer_dst->properties_evaluated = NULL;
+ view_layer_dst->properties = IDP_New(IDP_GROUP, &val, ROOT_PROP);
+ IDP_MergeGroup_ex(view_layer_dst->properties, view_layer_src->properties, true, flag);
+
+ /* we start fresh with no overrides and no visibility flags set
+ * instead of syncing both trees we simply unlink and relink the scene collection */
+ BLI_listbase_clear(&view_layer_dst->layer_collections);
+ BLI_listbase_clear(&view_layer_dst->object_bases);
+ BLI_listbase_clear(&view_layer_dst->drawdata);
+
+ layer_collections_recreate(view_layer_dst, &view_layer_src->layer_collections, mc_dst, mc_src);
+
+ /* Now we handle the syncing for visibility, selectability, ... */
+ layer_collections_sync_flags(&view_layer_dst->layer_collections, &view_layer_src->layer_collections);
+
+ Object *active_ob = OBACT(view_layer_src);
+ for (Base *base_src = view_layer_src->object_bases.first, *base_dst = view_layer_dst->object_bases.first;
+ base_src;
+ base_src = base_src->next, base_dst = base_dst->next)
+ {
+ base_dst->flag = base_src->flag;
+ base_dst->flag_legacy = base_src->flag_legacy;
+
+ if (base_dst->object == active_ob) {
+ view_layer_dst->basact = base_dst;
+ }
+ }
+}
+
static void view_layer_object_base_unref(ViewLayer *view_layer, Base *base)
{
base->refcount--;
@@ -416,7 +575,7 @@ LayerCollection *BKE_layer_collection_get_active_ensure(Scene *scene, ViewLayer
if (lc == NULL) {
BLI_assert(BLI_listbase_is_empty(&view_layer->layer_collections));
/* When there is no collection linked to this ViewLayer, create one. */
- SceneCollection *sc = BKE_collection_add(scene, NULL, NULL);
+ SceneCollection *sc = BKE_collection_add(&scene->id, NULL, COLLECTION_TYPE_NONE, NULL);
lc = BKE_collection_link(view_layer, sc);
/* New collection has to be the active one. */
BLI_assert(lc == BKE_layer_collection_get_active(view_layer));
@@ -552,15 +711,15 @@ static void layer_collection_swap(
}
/**
- * Move \a lc_src into \a lc_dst. Both have to be stored in \a sl.
+ * Move \a lc_src into \a lc_dst. Both have to be stored in \a view_layer.
* If \a lc_src is directly linked to the ViewLayer it's unlinked
*/
-bool BKE_layer_collection_move_into(const Scene *scene, LayerCollection *lc_dst, LayerCollection *lc_src)
+bool BKE_layer_collection_move_into(const ID *owner_id, LayerCollection *lc_dst, LayerCollection *lc_src)
{
- ViewLayer *view_layer = BKE_view_layer_find_from_collection(scene, lc_src);
+ ViewLayer *view_layer = BKE_view_layer_find_from_collection(owner_id, lc_src);
bool is_directly_linked = false;
- if ((!view_layer) || (view_layer != BKE_view_layer_find_from_collection(scene, lc_dst))) {
+ if ((!view_layer) || (view_layer != BKE_view_layer_find_from_collection(owner_id, lc_dst))) {
return false;
}
@@ -596,7 +755,7 @@ bool BKE_layer_collection_move_into(const Scene *scene, LayerCollection *lc_dst,
layer_collection_swap(view_layer, &view_layer->layer_collections, NULL, lc_temp, lc_src);
}
- if (!BKE_collection_move_into(scene, lc_dst->scene_collection, lc_src->scene_collection)) {
+ if (!BKE_collection_move_into(owner_id, lc_dst->scene_collection, lc_src->scene_collection)) {
if (!is_directly_linked) {
/* Swap back and remove */
layer_collection_swap(view_layer, NULL, NULL, lc_temp, lc_src);
@@ -606,7 +765,8 @@ bool BKE_layer_collection_move_into(const Scene *scene, LayerCollection *lc_dst,
}
}
- LayerCollection *lc_new = BLI_findptr(&lc_dst->layer_collections, lc_src->scene_collection, offsetof(LayerCollection, scene_collection));
+ LayerCollection *lc_new = BLI_findptr(
+ &lc_dst->layer_collections, lc_src->scene_collection, offsetof(LayerCollection, scene_collection));
BLI_assert(lc_new);
layer_collection_swap(view_layer, &lc_dst->layer_collections, NULL, lc_new, lc_src);
@@ -622,13 +782,13 @@ bool BKE_layer_collection_move_into(const Scene *scene, LayerCollection *lc_dst,
* Move \a lc_src above \a lc_dst. Both have to be stored in \a view_layer.
* If \a lc_src is directly linked to the ViewLayer it's unlinked
*/
-bool BKE_layer_collection_move_above(const Scene *scene, LayerCollection *lc_dst, LayerCollection *lc_src)
+bool BKE_layer_collection_move_above(const ID *owner_id, LayerCollection *lc_dst, LayerCollection *lc_src)
{
- ViewLayer *view_layer = BKE_view_layer_find_from_collection(scene, lc_src);
+ ViewLayer *view_layer = BKE_view_layer_find_from_collection(owner_id, lc_src);
const bool is_directly_linked_src = BLI_findindex(&view_layer->layer_collections, lc_src) != -1;
const bool is_directly_linked_dst = BLI_findindex(&view_layer->layer_collections, lc_dst) != -1;
- if ((!view_layer) || (view_layer != BKE_view_layer_find_from_collection(scene, lc_dst))) {
+ if ((!view_layer) || (view_layer != BKE_view_layer_find_from_collection(owner_id, lc_dst))) {
return false;
}
@@ -671,7 +831,7 @@ bool BKE_layer_collection_move_above(const Scene *scene, LayerCollection *lc_dst
layer_collection_swap(view_layer, &view_layer->layer_collections, NULL, lc_temp, lc_src);
}
- if (!BKE_collection_move_above(scene, lc_dst->scene_collection, lc_src->scene_collection)) {
+ if (!BKE_collection_move_above(owner_id, lc_dst->scene_collection, lc_src->scene_collection)) {
if (!is_directly_linked_src) {
/* Swap back and remove */
layer_collection_swap(view_layer, NULL, NULL, lc_temp, lc_src);
@@ -694,16 +854,16 @@ bool BKE_layer_collection_move_above(const Scene *scene, LayerCollection *lc_dst
}
/**
- * Move \a lc_src below \a lc_dst. Both have to be stored in \a sl.
+ * Move \a lc_src below \a lc_dst. Both have to be stored in \a view_layer.
* If \a lc_src is directly linked to the ViewLayer it's unlinked
*/
-bool BKE_layer_collection_move_below(const Scene *scene, LayerCollection *lc_dst, LayerCollection *lc_src)
+bool BKE_layer_collection_move_below(const ID *owner_id, LayerCollection *lc_dst, LayerCollection *lc_src)
{
- ViewLayer *view_layer = BKE_view_layer_find_from_collection(scene, lc_src);
+ ViewLayer *view_layer = BKE_view_layer_find_from_collection(owner_id, lc_src);
const bool is_directly_linked_src = BLI_findindex(&view_layer->layer_collections, lc_src) != -1;
const bool is_directly_linked_dst = BLI_findindex(&view_layer->layer_collections, lc_dst) != -1;
- if ((!view_layer) || (view_layer != BKE_view_layer_find_from_collection(scene, lc_dst))) {
+ if ((!view_layer) || (view_layer != BKE_view_layer_find_from_collection(owner_id, lc_dst))) {
return false;
}
@@ -746,7 +906,7 @@ bool BKE_layer_collection_move_below(const Scene *scene, LayerCollection *lc_dst
layer_collection_swap(view_layer, &view_layer->layer_collections, NULL, lc_temp, lc_src);
}
- if (!BKE_collection_move_below(scene, lc_dst->scene_collection, lc_src->scene_collection)) {
+ if (!BKE_collection_move_below(owner_id, lc_dst->scene_collection, lc_src->scene_collection)) {
if (!is_directly_linked_src) {
/* Swap back and remove */
layer_collection_swap(view_layer, NULL, NULL, lc_temp, lc_src);
@@ -809,9 +969,9 @@ static bool layer_collection_resync(ViewLayer *view_layer, LayerCollection *lc,
* Update the scene layers so that any LayerCollection that points
* to \a sc is re-synced again
*/
-void BKE_layer_collection_resync(const Scene *scene, const SceneCollection *sc)
+void BKE_layer_collection_resync(const ID *owner_id, const SceneCollection *sc)
{
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ for (ViewLayer *view_layer = BKE_view_layer_first_from_id(owner_id); view_layer; view_layer = view_layer->next) {
for (LayerCollection *lc = view_layer->layer_collections.first; lc; lc = lc->next) {
layer_collection_resync(view_layer, lc, sc);
}
@@ -1025,9 +1185,9 @@ static LayerCollection *find_layer_collection_by_scene_collection(LayerCollectio
/**
* Add a new LayerCollection for all the ViewLayers that have sc_parent
*/
-void BKE_layer_sync_new_scene_collection(Scene *scene, const SceneCollection *sc_parent, SceneCollection *sc)
+void BKE_layer_sync_new_scene_collection(ID *owner_id, const SceneCollection *sc_parent, SceneCollection *sc)
{
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ for (ViewLayer *view_layer = BKE_view_layer_first_from_id(owner_id); view_layer; view_layer = view_layer->next) {
for (LayerCollection *lc = view_layer->layer_collections.first; lc; lc = lc->next) {
LayerCollection *lc_parent = find_layer_collection_by_scene_collection(lc, sc_parent);
if (lc_parent) {
@@ -1040,9 +1200,9 @@ void BKE_layer_sync_new_scene_collection(Scene *scene, const SceneCollection *sc
/**
* Add a corresponding ObjectBase to all the equivalent LayerCollection
*/
-void BKE_layer_sync_object_link(const Scene *scene, SceneCollection *sc, Object *ob)
+void BKE_layer_sync_object_link(const ID *owner_id, SceneCollection *sc, Object *ob)
{
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ for (ViewLayer *view_layer = BKE_view_layer_first_from_id(owner_id); view_layer; view_layer = view_layer->next) {
for (LayerCollection *lc = view_layer->layer_collections.first; lc; lc = lc->next) {
LayerCollection *found = find_layer_collection_by_scene_collection(lc, sc);
if (found) {
@@ -1056,9 +1216,9 @@ void BKE_layer_sync_object_link(const Scene *scene, SceneCollection *sc, Object
* Remove the equivalent object base to all layers that have this collection
* also remove all reference to ob in the filter_objects
*/
-void BKE_layer_sync_object_unlink(const Scene *scene, SceneCollection *sc, Object *ob)
+void BKE_layer_sync_object_unlink(const ID *owner_id, SceneCollection *sc, Object *ob)
{
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ for (ViewLayer *view_layer = BKE_view_layer_first_from_id(owner_id); view_layer; view_layer = view_layer->next) {
for (LayerCollection *lc = view_layer->layer_collections.first; lc; lc = lc->next) {
LayerCollection *found = find_layer_collection_by_scene_collection(lc, sc);
if (found) {
@@ -1074,9 +1234,9 @@ void BKE_layer_sync_object_unlink(const Scene *scene, SceneCollection *sc, Objec
/**
* Add a new datablock override
*/
-void BKE_override_view_layer_datablock_add(ViewLayer *view_layer, int id_type, const char *data_path, const ID *id)
+void BKE_override_view_layer_datablock_add(ViewLayer *view_layer, int id_type, const char *data_path, const ID *owner_id)
{
- UNUSED_VARS(view_layer, id_type, data_path, id);
+ UNUSED_VARS(view_layer, id_type, data_path, owner_id);
TODO_LAYER_OVERRIDE;
}
@@ -1934,32 +2094,43 @@ static void idproperty_reset(IDProperty **props, IDProperty *props_ref)
}
void BKE_layer_eval_layer_collection_pre(const struct EvaluationContext *UNUSED(eval_ctx),
- Scene *scene, ViewLayer *view_layer)
+ ID *owner_id, ViewLayer *view_layer)
{
- DEBUG_PRINT("%s on scene:%s %s (%p)\n", __func__, scene->id.name, view_layer->name, view_layer);
+ DEBUG_PRINT("%s on %s (%p)\n", __func__, view_layer->name, view_layer);
+ Scene *scene = (GS(owner_id->name) == ID_SCE) ? (Scene *)owner_id : NULL;
+
for (Base *base = view_layer->object_bases.first; base != NULL; base = base->next) {
base->flag &= ~(BASE_VISIBLED | BASE_SELECTABLED);
- idproperty_reset(&base->collection_properties, scene->collection_properties);
+ idproperty_reset(&base->collection_properties, scene ? scene->collection_properties : NULL);
}
/* Sync properties from scene to scene layer. */
- idproperty_reset(&view_layer->properties_evaluated, scene->layer_properties);
+ idproperty_reset(&view_layer->properties_evaluated, scene ? scene->layer_properties : NULL);
IDP_MergeGroup(view_layer->properties_evaluated, view_layer->properties, true);
/* TODO(sergey): Is it always required? */
view_layer->flag |= VIEW_LAYER_ENGINE_DIRTY;
}
+static const char *collection_type_lookup[] =
+{
+ "None", /* COLLECTION_TYPE_NONE */
+ "Group Internal", /* COLLECTION_TYPE_GROUP_INTERNAL */
+};
+
void BKE_layer_eval_layer_collection(const struct EvaluationContext *UNUSED(eval_ctx),
LayerCollection *layer_collection,
LayerCollection *parent_layer_collection)
{
- DEBUG_PRINT("%s on %s (%p), parent %s (%p)\n",
+ DEBUG_PRINT("%s on %s (%p) [%s], parent %s (%p) [%s]\n",
__func__,
layer_collection->scene_collection->name,
layer_collection->scene_collection,
+ collection_type_lookup[layer_collection->scene_collection->type],
(parent_layer_collection != NULL) ? parent_layer_collection->scene_collection->name : "NONE",
- (parent_layer_collection != NULL) ? parent_layer_collection->scene_collection : NULL);
+ (parent_layer_collection != NULL) ? parent_layer_collection->scene_collection : NULL,
+ (parent_layer_collection != NULL) ? collection_type_lookup[parent_layer_collection->scene_collection->type] : "");
+ BLI_assert(layer_collection != parent_layer_collection);
/* visibility */
layer_collection->flag_evaluated = layer_collection->flag;
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 99dd6f86549..0ef1fe52994 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -104,6 +104,7 @@
#include "BKE_lamp.h"
#include "BKE_lattice.h"
#include "BKE_library.h"
+#include "BKE_library_override.h"
#include "BKE_library_query.h"
#include "BKE_library_remap.h"
#include "BKE_linestyle.h"
@@ -674,8 +675,12 @@ bool BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag, con
/* Do not make new copy local in case we are copying outside of main...
* XXX TODO: is this behavior OK, or should we need own flag to control that? */
if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
+ BLI_assert((flag & LIB_ID_COPY_KEEP_LIB) == 0);
BKE_id_copy_ensure_local(bmain, id, *r_newid);
}
+ else {
+ (*r_newid)->lib = id->lib;
+ }
return true;
}
@@ -689,6 +694,75 @@ bool id_copy(Main *bmain, const ID *id, ID **newid, bool test)
return BKE_id_copy_ex(bmain, id, newid, 0, test);
}
+/** Does a mere memory swap over the whole IDs data (including type-specific memory).
+ * \note Most internal ID data itself is not swapped (only IDProperties are). */
+void BKE_id_swap(Main *bmain, ID *id_a, ID *id_b)
+{
+ BLI_assert(GS(id_a->name) == GS(id_b->name));
+
+ const ID id_a_back = *id_a;
+ const ID id_b_back = *id_b;
+
+#define CASE_SWAP(_gs, _type) \
+ case _gs: \
+ SWAP(_type, *(_type *)id_a, *(_type *)id_b); \
+ break
+
+ switch ((ID_Type)GS(id_a->name)) {
+ CASE_SWAP(ID_SCE, Scene);
+ CASE_SWAP(ID_LI, Library);
+ CASE_SWAP(ID_OB, Object);
+ CASE_SWAP(ID_ME, Mesh);
+ CASE_SWAP(ID_CU, Curve);
+ CASE_SWAP(ID_MB, MetaBall);
+ CASE_SWAP(ID_MA, Material);
+ CASE_SWAP(ID_TE, Tex);
+ CASE_SWAP(ID_IM, Image);
+ CASE_SWAP(ID_LT, Lattice);
+ CASE_SWAP(ID_LA, Lamp);
+ CASE_SWAP(ID_LP, LightProbe);
+ CASE_SWAP(ID_CA, Camera);
+ CASE_SWAP(ID_KE, Key);
+ CASE_SWAP(ID_WO, World);
+ CASE_SWAP(ID_SCR, bScreen);
+ CASE_SWAP(ID_VF, VFont);
+ CASE_SWAP(ID_TXT, Text);
+ CASE_SWAP(ID_SPK, Speaker);
+ CASE_SWAP(ID_SO, bSound);
+ CASE_SWAP(ID_GR, Group);
+ CASE_SWAP(ID_AR, bArmature);
+ CASE_SWAP(ID_AC, bAction);
+ CASE_SWAP(ID_NT, bNodeTree);
+ CASE_SWAP(ID_BR, Brush);
+ CASE_SWAP(ID_PA, ParticleSettings);
+ CASE_SWAP(ID_WM, wmWindowManager);
+ CASE_SWAP(ID_WS, WorkSpace);
+ CASE_SWAP(ID_GD, bGPdata);
+ CASE_SWAP(ID_MC, MovieClip);
+ CASE_SWAP(ID_MSK, Mask);
+ CASE_SWAP(ID_LS, FreestyleLineStyle);
+ CASE_SWAP(ID_PAL, Palette);
+ CASE_SWAP(ID_PC, PaintCurve);
+ CASE_SWAP(ID_CF, CacheFile);
+ case ID_IP:
+ break; /* Deprecated. */
+ }
+
+#undef CASE_SWAP
+
+ /* Restore original ID's internal data. */
+ *id_a = id_a_back;
+ *id_b = id_b_back;
+
+ /* Exception: IDProperties. */
+ id_a->properties = id_b_back.properties;
+ id_b->properties = id_a_back.properties;
+
+ /* Swap will have broken internal references to itself, restore them. */
+ BKE_libblock_relink_ex(bmain, id_a, id_b, id_a, false);
+ BKE_libblock_relink_ex(bmain, id_b, id_a, id_b, false);
+}
+
/** Does *not* set ID->newid pointer. */
bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop)
{
@@ -1342,6 +1416,15 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int fla
new_id->properties = IDP_CopyProperty_ex(id->properties, flag);
}
+ /* XXX Again... We need a way to control what we copy in a much more refined way.
+ * We cannot always copy this, some internal copying will die on it! */
+ /* For now, upper level code will have to do that itself when required. */
+#if 0
+ if (id->override != NULL) {
+ BKE_override_copy(new_id, id);
+ }
+#endif
+
/* the duplicate should get a copy of the animdata */
id_copy_animdata(bmain, new_id, (flag & LIB_ID_COPY_ACTIONS) != 0 && (flag & LIB_ID_CREATE_NO_MAIN) == 0);
diff --git a/source/blender/blenkernel/intern/library_override.c b/source/blender/blenkernel/intern/library_override.c
new file mode 100644
index 00000000000..22896cff64a
--- /dev/null
+++ b/source/blender/blenkernel/intern/library_override.c
@@ -0,0 +1,680 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Bastien Montagne.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/library_override.c
+ * \ingroup bke
+ */
+
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_ID.h"
+#include "DNA_object_types.h"
+
+#include "DEG_depsgraph.h"
+#include "BKE_library.h"
+#include "BKE_library_override.h"
+#include "BKE_library_remap.h"
+#include "BKE_main.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+#include "RNA_access.h"
+#include "RNA_types.h"
+
+#include "PIL_time.h"
+#include "PIL_time_utildefines.h"
+
+#define OVERRIDE_AUTO_CHECK_DELAY 0.2 /* 200ms between auto-override checks. */
+
+static void bke_override_property_copy(IDOverrideStaticProperty *op_dst, IDOverrideStaticProperty *op_src);
+static void bke_override_property_operation_copy(IDOverrideStaticPropertyOperation *opop_dst, IDOverrideStaticPropertyOperation *opop_src);
+
+static void bke_override_property_clear(IDOverrideStaticProperty *op);
+static void bke_override_property_operation_clear(IDOverrideStaticPropertyOperation *opop);
+
+/** Initialize empty overriding of \a reference_id by \a local_id. */
+IDOverrideStatic *BKE_override_static_init(ID *local_id, ID *reference_id)
+{
+ /* If reference_id is NULL, we are creating an override template for purely local data.
+ * Else, reference *must* be linked data. */
+ BLI_assert(reference_id == NULL || reference_id->lib != NULL);
+ BLI_assert(local_id->override_static == NULL);
+
+ if (reference_id != NULL && reference_id->override_static != NULL && reference_id->override_static->reference == NULL) {
+ /* reference ID has an override template, use it! */
+ BKE_override_static_copy(local_id, reference_id);
+ return local_id->override_static;
+ }
+
+ /* Else, generate new empty override. */
+ local_id->override_static = MEM_callocN(sizeof(*local_id->override_static), __func__);
+ local_id->override_static->reference = reference_id;
+ id_us_plus(reference_id);
+ local_id->tag &= ~LIB_TAG_OVERRIDESTATIC_OK;
+ /* TODO do we want to add tag or flag to referee to mark it as such? */
+ return local_id->override_static;
+}
+
+/** Deep copy of a whole override from \a src_id to \a dst_id. */
+void BKE_override_static_copy(ID *dst_id, const ID *src_id)
+{
+ BLI_assert(src_id->override_static != NULL);
+
+ if (dst_id->override_static != NULL) {
+ if (src_id->override_static == NULL) {
+ BKE_override_static_free(&dst_id->override_static);
+ return;
+ }
+ else {
+ BKE_override_static_clear(dst_id->override_static);
+ }
+ }
+ else if (src_id->override_static == NULL) {
+ return;
+ }
+ else {
+ BKE_override_static_init(dst_id, NULL);
+ }
+
+ /* Source is already overriding data, we copy it but reuse its reference for dest ID.
+ * otherwise, source is only an override template, it then becomes reference of dest ID. */
+ dst_id->override_static->reference = src_id->override_static->reference ? src_id->override_static->reference : (ID *)src_id;
+ id_us_plus(dst_id->override_static->reference);
+
+ BLI_duplicatelist(&dst_id->override_static->properties, &src_id->override_static->properties);
+ for (IDOverrideStaticProperty *op_dst = dst_id->override_static->properties.first, *op_src = src_id->override_static->properties.first;
+ op_dst;
+ op_dst = op_dst->next, op_src = op_src->next)
+ {
+ bke_override_property_copy(op_dst, op_src);
+ }
+
+ dst_id->tag &= ~LIB_TAG_OVERRIDESTATIC_OK;
+}
+
+/** Clear any overriding data from given \a override. */
+void BKE_override_static_clear(IDOverrideStatic *override)
+{
+ BLI_assert(override != NULL);
+
+ for (IDOverrideStaticProperty *op = override->properties.first; op; op = op->next) {
+ bke_override_property_clear(op);
+ }
+ BLI_freelistN(&override->properties);
+
+ id_us_min(override->reference);
+ /* override->storage should never be refcounted... */
+}
+
+/** Free given \a override. */
+void BKE_override_static_free(struct IDOverrideStatic **override)
+{
+ BLI_assert(*override != NULL);
+
+ BKE_override_static_clear(*override);
+ MEM_freeN(*override);
+ *override = NULL;
+}
+
+/** Create an overriden local copy of linked reference. */
+ID *BKE_override_static_create_from(Main *bmain, ID *reference_id)
+{
+ BLI_assert(reference_id != NULL);
+ BLI_assert(reference_id->lib != NULL);
+
+ ID *local_id;
+
+ if (!id_copy(bmain, reference_id, (ID **)&local_id, false)) {
+ return NULL;
+ }
+ id_us_min(local_id);
+
+ BKE_override_static_init(local_id, reference_id);
+ local_id->flag |= LIB_OVERRIDE_STATIC_AUTO;
+
+ /* Remapping, we obviously only want to affect local data (and not our own reference pointer to overriden ID). */
+ BKE_libblock_remap(bmain, reference_id, local_id, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_STATIC_OVERRIDE);
+
+ return local_id;
+}
+
+/**
+ * Find override property from given RNA path, if it exists.
+ */
+IDOverrideStaticProperty *BKE_override_static_property_find(IDOverrideStatic *override, const char *rna_path)
+{
+ /* XXX TODO we'll most likely want a runtime ghash to store that mapping at some point. */
+ return BLI_findstring_ptr(&override->properties, rna_path, offsetof(IDOverrideStaticProperty, rna_path));
+}
+
+/**
+ * Find override property from given RNA path, or create it if it does not exist.
+ */
+IDOverrideStaticProperty *BKE_override_static_property_get(IDOverrideStatic *override, const char *rna_path, bool *r_created)
+{
+ /* XXX TODO we'll most likely want a runtime ghash to store taht mapping at some point. */
+ IDOverrideStaticProperty *op = BKE_override_static_property_find(override, rna_path);
+
+ if (op == NULL) {
+ op = MEM_callocN(sizeof(IDOverrideStaticProperty), __func__);
+ op->rna_path = BLI_strdup(rna_path);
+ BLI_addtail(&override->properties, op);
+
+ if (r_created) {
+ *r_created = true;
+ }
+ }
+ else if (r_created) {
+ *r_created = false;
+ }
+
+ return op;
+}
+
+void bke_override_property_copy(IDOverrideStaticProperty *op_dst, IDOverrideStaticProperty *op_src)
+{
+ op_dst->rna_path = BLI_strdup(op_src->rna_path);
+ BLI_duplicatelist(&op_dst->operations, &op_src->operations);
+
+ for (IDOverrideStaticPropertyOperation *opop_dst = op_dst->operations.first, *opop_src = op_src->operations.first;
+ opop_dst;
+ opop_dst = opop_dst->next, opop_src = opop_src->next)
+ {
+ bke_override_property_operation_copy(opop_dst, opop_src);
+ }
+}
+
+void bke_override_property_clear(IDOverrideStaticProperty *op)
+{
+ BLI_assert(op->rna_path != NULL);
+
+ MEM_freeN(op->rna_path);
+
+ for (IDOverrideStaticPropertyOperation *opop = op->operations.first; opop; opop = opop->next) {
+ bke_override_property_operation_clear(opop);
+ }
+ BLI_freelistN(&op->operations);
+}
+
+/**
+ * Remove and free given \a override_property from given ID \a override.
+ */
+void BKE_override_static_property_delete(IDOverrideStatic *override, IDOverrideStaticProperty *override_property)
+{
+ bke_override_property_clear(override_property);
+ BLI_freelinkN(&override->properties, override_property);
+}
+
+/**
+ * Find override property operation from given sub-item(s), if it exists.
+ */
+IDOverrideStaticPropertyOperation *BKE_override_static_property_operation_find(
+ IDOverrideStaticProperty *override_property,
+ const char *subitem_refname, const char *subitem_locname,
+ const int subitem_refindex, const int subitem_locindex, const bool strict, bool *r_strict)
+{
+ IDOverrideStaticPropertyOperation *opop;
+ const int subitem_defindex = -1;
+
+ if (r_strict) {
+ *r_strict = true;
+ }
+
+ if (subitem_locname &&
+ (opop = BLI_findstring_ptr(&override_property->operations, subitem_locname,
+ offsetof(IDOverrideStaticPropertyOperation, subitem_local_name))))
+ {
+ return opop;
+ }
+
+ if (subitem_refname &&
+ (opop = BLI_findstring_ptr(&override_property->operations, subitem_refname,
+ offsetof(IDOverrideStaticPropertyOperation, subitem_reference_name))))
+ {
+ return opop;
+ }
+
+ if ((opop = BLI_listbase_bytes_find(&override_property->operations, &subitem_locindex, sizeof(subitem_locindex),
+ offsetof(IDOverrideStaticPropertyOperation, subitem_local_index))))
+ {
+ return opop;
+ }
+
+ if ((opop = BLI_listbase_bytes_find(&override_property->operations, &subitem_refindex, sizeof(subitem_refindex),
+ offsetof(IDOverrideStaticPropertyOperation, subitem_reference_index))))
+ {
+ return opop;
+ }
+
+ /* index == -1 means all indices, that is valid fallback in case we requested specific index. */
+ if (!strict && (subitem_locindex != subitem_defindex) &&
+ (opop = BLI_listbase_bytes_find(&override_property->operations, &subitem_defindex, sizeof(subitem_defindex),
+ offsetof(IDOverrideStaticPropertyOperation, subitem_local_index))))
+ {
+ if (r_strict) {
+ *r_strict = false;
+ }
+ return opop;
+ }
+
+ return NULL;
+}
+
+/**
+ * Find override property operation from given sub-item(s), or create it if it does not exist.
+ */
+IDOverrideStaticPropertyOperation *BKE_override_static_property_operation_get(
+ IDOverrideStaticProperty *override_property, const short operation,
+ const char *subitem_refname, const char *subitem_locname,
+ const int subitem_refindex, const int subitem_locindex,
+ const bool strict, bool *r_strict, bool *r_created)
+{
+ IDOverrideStaticPropertyOperation *opop = BKE_override_static_property_operation_find(override_property,
+ subitem_refname, subitem_locname,
+ subitem_refindex, subitem_locindex,
+ strict, r_strict);
+
+ if (opop == NULL) {
+ opop = MEM_callocN(sizeof(IDOverrideStaticPropertyOperation), __func__);
+ opop->operation = operation;
+ if (subitem_locname) {
+ opop->subitem_local_name = BLI_strdup(subitem_locname);
+ }
+ if (subitem_refname) {
+ opop->subitem_reference_name = BLI_strdup(subitem_refname);
+ }
+ opop->subitem_local_index = subitem_locindex;
+ opop->subitem_reference_index = subitem_refindex;
+
+ BLI_addtail(&override_property->operations, opop);
+
+ if (r_created) {
+ *r_created = true;
+ }
+ }
+ else if (r_created) {
+ *r_created = false;
+ }
+
+ return opop;
+}
+
+void bke_override_property_operation_copy(IDOverrideStaticPropertyOperation *opop_dst, IDOverrideStaticPropertyOperation *opop_src)
+{
+ if (opop_src->subitem_reference_name) {
+ opop_dst->subitem_reference_name = BLI_strdup(opop_src->subitem_reference_name);
+ }
+ if (opop_src->subitem_local_name) {
+ opop_dst->subitem_local_name = BLI_strdup(opop_src->subitem_local_name);
+ }
+}
+
+void bke_override_property_operation_clear(IDOverrideStaticPropertyOperation *opop)
+{
+ if (opop->subitem_reference_name) {
+ MEM_freeN(opop->subitem_reference_name);
+ }
+ if (opop->subitem_local_name) {
+ MEM_freeN(opop->subitem_local_name);
+ }
+}
+
+/**
+ * Remove and free given \a override_property_operation from given ID \a override_property.
+ */
+void BKE_override_static_property_operation_delete(
+ IDOverrideStaticProperty *override_property, IDOverrideStaticPropertyOperation *override_property_operation)
+{
+ bke_override_property_operation_clear(override_property_operation);
+ BLI_freelinkN(&override_property->operations, override_property_operation);
+}
+
+/**
+ * Check that status of local data-block is still valid against current reference one.
+ *
+ * It means that all overridable, but not overridden, properties' local values must be equal to reference ones.
+ * Clears LIB_TAG_OVERRIDE_OK if they do not.
+ *
+ * This is typically used to detect whether some property has been changed in local and a new IDOverrideProperty
+ * (of IDOverridePropertyOperation) has to be added.
+ *
+ * \return true if status is OK, false otherwise. */
+bool BKE_override_static_status_check_local(ID *local)
+{
+ BLI_assert(local->override_static != NULL);
+
+ ID *reference = local->override_static->reference;
+
+ if (reference == NULL) {
+ /* This is an override template, local status is always OK! */
+ return true;
+ }
+
+ BLI_assert(GS(local->name) == GS(reference->name));
+
+ /* Note that reference is assumed always valid, caller has to ensure that itself. */
+
+ PointerRNA rnaptr_local, rnaptr_reference;
+ RNA_id_pointer_create(local, &rnaptr_local);
+ RNA_id_pointer_create(reference, &rnaptr_reference);
+
+ if (!RNA_struct_override_matches(&rnaptr_local, &rnaptr_reference, local->override_static, true, true)) {
+ local->tag &= ~LIB_TAG_OVERRIDESTATIC_OK;
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Check that status of reference data-block is still valid against current local one.
+ *
+ * It means that all non-overridden properties' local values must be equal to reference ones.
+ * Clears LIB_TAG_OVERRIDE_OK if they do not.
+ *
+ * This is typically used to detect whether some reference has changed and local needs to be updated against it.
+ *
+ * \return true if status is OK, false otherwise. */
+bool BKE_override_static_status_check_reference(ID *local)
+{
+ BLI_assert(local->override_static != NULL);
+
+ ID *reference = local->override_static->reference;
+
+ if (reference == NULL) {
+ /* This is an override template, reference is virtual, so its status is always OK! */
+ return true;
+ }
+
+ BLI_assert(GS(local->name) == GS(reference->name));
+
+ if (reference->override_static && (reference->tag & LIB_TAG_OVERRIDESTATIC_OK) == 0) {
+ if (!BKE_override_static_status_check_reference(reference)) {
+ /* If reference is also override of another data-block, and its status is not OK,
+ * then this override is not OK either.
+ * Note that this should only happen when reloading libraries... */
+ local->tag &= ~LIB_TAG_OVERRIDESTATIC_OK;
+ return false;
+ }
+ }
+
+ PointerRNA rnaptr_local, rnaptr_reference;
+ RNA_id_pointer_create(local, &rnaptr_local);
+ RNA_id_pointer_create(reference, &rnaptr_reference);
+
+ if (!RNA_struct_override_matches(&rnaptr_local, &rnaptr_reference, local->override_static, false, true)) {
+ local->tag &= ~LIB_TAG_OVERRIDESTATIC_OK;
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Compares local and reference data-blocks and create new override operations as needed,
+ * or reset to reference values if overriding is not allowed.
+ *
+ * \note Defining override operations is only mandatory before saving a .blend file on disk (not for undo!).
+ * Knowing that info at runtime is only useful for UI/UX feedback.
+ *
+ * \note This is by far the biggest operation (the more time-consuming) of the three so far, since it has to go over
+ * all properties in depth (all overridable ones at least). Generating diff values and applying overrides
+ * are much cheaper.
+ *
+ * \return true is new overriding op was created, or some local data was reset. */
+bool BKE_override_static_operations_create(ID *local)
+{
+ BLI_assert(local->override_static != NULL);
+ const bool is_template = (local->override_static->reference == NULL);
+ bool ret = false;
+
+ if (!is_template && local->flag & LIB_OVERRIDE_STATIC_AUTO) {
+ PointerRNA rnaptr_local, rnaptr_reference;
+ RNA_id_pointer_create(local, &rnaptr_local);
+ RNA_id_pointer_create(local->override_static->reference, &rnaptr_reference);
+
+ ret = RNA_struct_auto_override(&rnaptr_local, &rnaptr_reference, local->override_static, NULL);
+#ifndef NDEBUG
+ if (ret) {
+ printf("We did generate static override rules for %s\n", local->name);
+ }
+ else {
+ printf("No new static override rules for %s\n", local->name);
+ }
+#endif
+ }
+ return ret;
+}
+
+/** Check all overrides from given \a bmain and create/update overriding operations as needed. */
+void BKE_main_override_static_operations_create(Main *bmain)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ int base_count, i;
+
+ base_count = set_listbasepointers(bmain, lbarray);
+
+ for (i = 0; i < base_count; i++) {
+ ListBase *lb = lbarray[i];
+ ID *id;
+
+ for (id = lb->first; id; id = id->next) {
+ /* TODO Maybe we could also add an 'override update' tag e.g. when tagging for DEG update? */
+ if (id->lib == NULL && id->override_static != NULL && id->override_static->reference != NULL && (id->flag & LIB_OVERRIDE_STATIC_AUTO)) {
+ BKE_override_static_operations_create(id);
+ }
+ }
+ }
+}
+
+/** Update given override from its reference (re-applying overriden properties). */
+void BKE_override_static_update(Main *bmain, ID *local)
+{
+ if (local->override_static == NULL || local->override_static->reference == NULL) {
+ return;
+ }
+
+ /* Recursively do 'ancestors' overrides first, if any. */
+ if (local->override_static->reference->override_static && (local->override_static->reference->tag & LIB_TAG_OVERRIDESTATIC_OK) == 0) {
+ BKE_override_static_update(bmain, local->override_static->reference);
+ }
+
+ /* We want to avoid having to remap here, however creating up-to-date override is much simpler if based
+ * on reference than on current override.
+ * So we work on temp copy of reference, and 'swap' its content with local. */
+
+ /* XXX We need a way to get off-Main copies of IDs (similar to localized mats/texts/ etc.)!
+ * However, this is whole bunch of code work in itself, so for now plain stupid ID copy will do,
+ * as innefficient as it is. :/
+ * Actually, maybe not! Since we are swapping with original ID's local content, we want to keep
+ * usercount in correct state when freeing tmp_id (and that usercounts of IDs used by 'new' local data
+ * also remain correct). */
+ /* This would imply change in handling of usercout all over RNA (and possibly all over Blender code).
+ * Not impossible to do, but would rather see first if extra useless usual user handling is actually
+ * a (performances) issue here. */
+
+ ID *tmp_id;
+ id_copy(bmain, local->override_static->reference, &tmp_id, false);
+
+ if (tmp_id == NULL) {
+ return;
+ }
+
+ PointerRNA rnaptr_src, rnaptr_dst, rnaptr_storage_stack, *rnaptr_storage = NULL;
+ RNA_id_pointer_create(local, &rnaptr_src);
+ RNA_id_pointer_create(tmp_id, &rnaptr_dst);
+ if (local->override_static->storage) {
+ rnaptr_storage = &rnaptr_storage_stack;
+ RNA_id_pointer_create(local->override_static->storage, rnaptr_storage);
+ }
+
+ RNA_struct_override_apply(&rnaptr_dst, &rnaptr_src, rnaptr_storage, local->override_static);
+
+ /* This also transfers all pointers (memory) owned by local to tmp_id, and vice-versa. So when we'll free tmp_id,
+ * we'll actually free old, outdated data from local. */
+ BKE_id_swap(bmain, local, tmp_id);
+
+ /* Again, horribly innefficient in our case, we need something off-Main (aka moar generic nolib copy/free stuff)! */
+ /* XXX And crashing in complex cases (e.g. because depsgraph uses same data...). */
+ BKE_libblock_free_ex(bmain, tmp_id, true, false);
+
+ if (local->override_static->storage) {
+ /* We know this datablock is not used anywhere besides local->override->storage. */
+ /* XXX For until we get fully shadow copies, we still need to ensure storage releases
+ * its usage of any ID pointers it may have. */
+ BKE_libblock_free_ex(bmain, local->override_static->storage, true, false);
+ local->override_static->storage = NULL;
+ }
+
+ local->tag |= LIB_TAG_OVERRIDESTATIC_OK;
+
+ /* Full rebuild of Depsgraph! */
+ DEG_on_visible_update(bmain, true); /* XXX Is this actual valid replacement for old DAG_relations_tag_update(bmain) ? */
+}
+
+/** Update all overrides from given \a bmain. */
+void BKE_main_override_static_update(Main *bmain)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ int base_count, i;
+
+ base_count = set_listbasepointers(bmain, lbarray);
+
+ for (i = 0; i < base_count; i++) {
+ ListBase *lb = lbarray[i];
+ ID *id;
+
+ for (id = lb->first; id; id = id->next) {
+ if (id->override_static != NULL && id->lib == NULL) {
+ BKE_override_static_update(bmain, id);
+ }
+ }
+ }
+}
+
+/***********************************************************************************************************************
+ * Storage (how to wtore overriding data into .blend files).
+ *
+ * Basically:
+ * I) Only 'differential' storage needs special handling here. All others (replacing values or
+ * inserting/removing items from a collection) can be handled with simply storing current content of local data-block.
+ * II) We store the differential value into a second 'ghost' data-block, which is an empty ID of same type as local one,
+ * where we only define values that need differential data.
+ *
+ * This avoids us having to modify 'real' data-block at write time (and retoring it afterwards), which is inneficient,
+ * and potentially dangerous (in case of concurrent access...), while not using much extra memory in typical cases.
+ * It also ensures stored data-block always contains exact same data as "desired" ones (kind of "baked" data-blocks).
+ */
+
+/** Initialize an override storage. */
+OverrideStaticStorage *BKE_override_static_operations_store_initialize(void)
+{
+ return BKE_main_new();
+}
+
+/**
+ * Generate suitable 'write' data (this only affects differential override operations).
+ *
+ * Note that \a local ID is no more modified by this call, all extra data are stored in its temp \a storage_id copy. */
+ID *BKE_override_static_operations_store_start(OverrideStaticStorage *override_storage, ID *local)
+{
+ BLI_assert(local->override_static != NULL);
+ BLI_assert(override_storage != NULL);
+ const bool is_template = (local->override_static->reference == NULL);
+
+ if (is_template) {
+ /* This is actually purely local data with an override template, nothing to do here! */
+ return NULL;
+ }
+
+ /* Forcefully ensure we know about all needed override operations. */
+ BKE_override_static_operations_create(local);
+
+ ID *storage_id;
+#ifdef DEBUG_OVERRIDE_TIMEIT
+ TIMEIT_START_AVERAGED(BKE_override_operations_store_start);
+#endif
+
+ /* XXX TODO We may also want a specialized handling of things here too, to avoid copying heavy never-overridable
+ * data (like Mesh geometry etc.)? And also maybe avoid lib refcounting completely (shallow copy...). */
+ /* This would imply change in handling of usercout all over RNA (and possibly all over Blender code).
+ * Not impossible to do, but would rather see first is extra useless usual user handling is actually
+ * a (performances) issue here, before doing it. */
+ id_copy((Main *)override_storage, local, &storage_id, false);
+
+ if (storage_id != NULL) {
+ PointerRNA rnaptr_reference, rnaptr_final, rnaptr_storage;
+ RNA_id_pointer_create(local->override_static->reference, &rnaptr_reference);
+ RNA_id_pointer_create(local, &rnaptr_final);
+ RNA_id_pointer_create(storage_id, &rnaptr_storage);
+
+ if (!RNA_struct_override_store(&rnaptr_final, &rnaptr_reference, &rnaptr_storage, local->override_static)) {
+ BKE_libblock_free_ex(override_storage, storage_id, true, false);
+ storage_id = NULL;
+ }
+ }
+
+ local->override_static->storage = storage_id;
+
+#ifdef DEBUG_OVERRIDE_TIMEIT
+ TIMEIT_END_AVERAGED(BKE_override_operations_store_start);
+#endif
+ return storage_id;
+}
+
+/** Restore given ID modified by \a BKE_override_operations_store_start, to its original state. */
+void BKE_override_static_operations_store_end(OverrideStaticStorage *UNUSED(override_storage), ID *local)
+{
+ BLI_assert(local->override_static != NULL);
+
+ /* Nothing else to do here really, we need to keep all temp override storage data-blocks in memory until
+ * whole file is written anyway (otherwise we'd get mem pointers overlap...). */
+ local->override_static->storage = NULL;
+}
+
+void BKE_override_static_operations_store_finalize(OverrideStaticStorage *override_storage)
+{
+ /* We cannot just call BKE_main_free(override_storage), not until we have option to make 'ghost' copies of IDs
+ * without increasing usercount of used data-blocks... */
+ ListBase *lbarray[MAX_LIBARRAY];
+ int base_count, i;
+
+ base_count = set_listbasepointers(override_storage, lbarray);
+
+ for (i = 0; i < base_count; i++) {
+ ListBase *lb = lbarray[i];
+ ID *id;
+
+ while ((id = lb->first)) {
+ BKE_libblock_free_ex(override_storage, id, true, false);
+ }
+ }
+
+ BKE_main_free(override_storage);
+}
diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c
index 93bc4be7954..e25a354c8af 100644
--- a/source/blender/blenkernel/intern/library_query.c
+++ b/source/blender/blenkernel/intern/library_query.c
@@ -75,6 +75,7 @@
#include "BKE_collection.h"
#include "BKE_constraint.h"
#include "BKE_fcurve.h"
+#include "BKE_group.h"
#include "BKE_idprop.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
@@ -373,6 +374,10 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
#define CALLBACK_INVOKE(check_id_super, cb_flag) \
FOREACH_CALLBACK_INVOKE(&data, check_id_super, cb_flag)
+ if (id->override_static != NULL) {
+ CALLBACK_INVOKE_ID(id->override_static->reference, IDWALK_CB_USER | IDWALK_CB_STATIC_OVERRIDE_REFERENCE);
+ }
+
for (; id != NULL; id = (flag & IDWALK_RECURSE) ? BLI_LINKSTACK_POP(data.ids_todo) : NULL) {
data.self_id = id;
data.cb_flag = ID_IS_LINKED(id) ? IDWALK_CB_INDIRECT_USAGE : 0;
@@ -768,10 +773,11 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
case ID_GR:
{
Group *group = (Group *) id;
- GroupObject *gob;
- for (gob = group->gobject.first; gob; gob = gob->next) {
- CALLBACK_INVOKE(gob->ob, IDWALK_CB_USER_ONE);
+ FOREACH_GROUP_OBJECT(group, object)
+ {
+ CALLBACK_INVOKE(object, IDWALK_CB_USER_ONE);
}
+ FOREACH_GROUP_OBJECT_END
break;
}
diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c
index e897f3c5330..fb672cb8b9f 100644
--- a/source/blender/blenkernel/intern/library_remap.c
+++ b/source/blender/blenkernel/intern/library_remap.c
@@ -87,6 +87,7 @@
#include "BKE_lattice.h"
#include "BKE_layer.h"
#include "BKE_library.h"
+#include "BKE_library_override.h"
#include "BKE_library_query.h"
#include "BKE_library_remap.h"
#include "BKE_linestyle.h"
@@ -181,6 +182,7 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
}
if (*id_p && (*id_p == old_id)) {
+ const bool is_reference = (cb_flag & IDWALK_CB_STATIC_OVERRIDE_REFERENCE) != 0;
const bool is_indirect = (cb_flag & IDWALK_CB_INDIRECT_USAGE) != 0;
const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0;
/* Note: proxy usage implies LIB_TAG_EXTERN, so on this aspect it is direct,
@@ -191,6 +193,7 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id));
const bool is_never_null = ((cb_flag & IDWALK_CB_NEVER_NULL) && (new_id == NULL) &&
(id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0);
+ const bool skip_reference = (id_remap_data->flag & ID_REMAP_SKIP_STATIC_OVERRIDE) != 0;
const bool skip_never_null = (id_remap_data->flag & ID_REMAP_SKIP_NEVER_NULL_USAGE) != 0;
#ifdef DEBUG_PRINT
@@ -205,7 +208,8 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
/* Special hack in case it's Object->data and we are in edit mode (skipped_direct too). */
if ((is_never_null && skip_never_null) ||
(is_obj_editmode && (((Object *)id)->data == *id_p)) ||
- (skip_indirect && is_indirect))
+ (skip_indirect && is_indirect) ||
+ (is_reference && skip_reference))
{
if (is_indirect) {
id_remap_data->skipped_indirect++;
@@ -218,7 +222,7 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
}
}
}
- else if (is_never_null || is_obj_editmode) {
+ else if (is_never_null || is_obj_editmode || is_reference) {
id_remap_data->skipped_direct++;
}
else {
@@ -266,7 +270,7 @@ static void libblock_remap_data_preprocess_scene_object_unlink(
r_id_remap_data->skipped_refcounted++;
}
else {
- BKE_collections_object_remove(r_id_remap_data->bmain, sce, ob, false);
+ BKE_collections_object_remove(r_id_remap_data->bmain, &sce->id, ob, false);
if (!is_indirect) {
r_id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT;
}
@@ -742,6 +746,10 @@ void BKE_libblock_free_data(ID *id, const bool do_id_user)
MEM_freeN(id->properties);
}
+ if (id->override_static) {
+ BKE_override_static_free(&id->override_static);
+ }
+
/* XXX TODO remove animdata handling from each type's freeing func, and do it here, like for copy! */
}
diff --git a/source/blender/blenkernel/intern/lightprobe.c b/source/blender/blenkernel/intern/lightprobe.c
index 03bd2344f7b..d5dbbe873a2 100644
--- a/source/blender/blenkernel/intern/lightprobe.c
+++ b/source/blender/blenkernel/intern/lightprobe.c
@@ -50,6 +50,8 @@ void BKE_lightprobe_init(LightProbe *probe)
probe->falloff = 0.2f;
probe->clipsta = 0.8f;
probe->clipend = 40.0f;
+ probe->vis_bias = 1.0f;
+ probe->vis_blur = 0.2f;
probe->data_draw_size = 1.0f;
probe->flag = LIGHTPROBE_FLAG_SHOW_INFLUENCE | LIGHTPROBE_FLAG_SHOW_DATA;
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 8fa4ebb8b3c..bea9e3bdcac 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -467,8 +467,6 @@ void BKE_object_free(Object *ob)
}
BLI_freelistN(&ob->drawdata);
- ob->deg_update_flag = 0;
-
BKE_sculptsession_free(ob);
BLI_freelistN(&ob->pc_ids);
@@ -706,6 +704,9 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
ob = BKE_libblock_alloc(bmain, ID_OB, name, 0);
+ /* We increase object user count when linking to SceneCollections. */
+ id_us_min(&ob->id);
+
/* default object vars */
ob->type = type;
@@ -745,7 +746,7 @@ Object *BKE_object_add(
ob = object_add_common(bmain, view_layer, type, name);
layer_collection = BKE_layer_collection_get_active_ensure(scene, view_layer);
- BKE_collection_object_add(scene, layer_collection->scene_collection, ob);
+ BKE_collection_object_add(&scene->id, layer_collection->scene_collection, ob);
base = BKE_view_layer_base_find(view_layer, ob);
BKE_view_layer_base_select(view_layer, base);
@@ -2663,6 +2664,28 @@ bool BKE_object_parent_loop_check(const Object *par, const Object *ob)
return BKE_object_parent_loop_check(par->parent, ob);
}
+static void object_handle_update_proxy(const EvaluationContext *eval_ctx,
+ Scene *scene,
+ Object *object,
+ const bool do_proxy_update)
+{
+ /* The case when this is a group proxy, object_update is called in group.c */
+ if (object->proxy == NULL) {
+ return;
+ }
+ /* set pointer in library proxy target, for copying, but restore it */
+ object->proxy->proxy_from = object;
+ // printf("set proxy pointer for later group stuff %s\n", ob->id.name);
+
+ /* the no-group proxy case, we call update */
+ if (object->proxy_group == NULL) {
+ if (do_proxy_update) {
+ // printf("call update, lib ob %s proxy %s\n", ob->proxy->id.name, ob->id.name);
+ BKE_object_handle_update(eval_ctx, scene, object->proxy);
+ }
+ }
+}
+
/* proxy rule: lib_object->proxy_from == the one we borrow from, only set temporal and cleared here */
/* local_object->proxy == pointer to library object, saved in files and read */
@@ -2676,75 +2699,51 @@ void BKE_object_handle_update_ex(const EvaluationContext *eval_ctx,
RigidBodyWorld *rbw,
const bool do_proxy_update)
{
- if (ob->recalc & OB_RECALC_ALL) {
- /* speed optimization for animation lookups */
- if (ob->pose) {
- BKE_pose_channels_hash_make(ob->pose);
- if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
- BKE_pose_update_constraint_flags(ob->pose);
- }
+ const bool recalc_object = (ob->id.tag & LIB_TAG_ID_RECALC) != 0;
+ const bool recalc_data = (ob->id.tag & LIB_TAG_ID_RECALC_DATA) != 0;
+ if (!recalc_object && ! recalc_data) {
+ object_handle_update_proxy(eval_ctx, scene, ob, do_proxy_update);
+ return;
+ }
+ /* Speed optimization for animation lookups. */
+ if (ob->pose != NULL) {
+ BKE_pose_channels_hash_make(ob->pose);
+ if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
+ BKE_pose_update_constraint_flags(ob->pose);
}
-
- if (ob->recalc & OB_RECALC_DATA) {
- if (ob->type == OB_ARMATURE) {
- /* this happens for reading old files and to match library armatures
- * with poses we do it ahead of BKE_object_where_is_calc to ensure animation
- * is evaluated on the rebuilt pose, otherwise we get incorrect poses
- * on file load */
- if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC))
- BKE_pose_rebuild(ob, ob->data);
- }
+ }
+ if (recalc_data) {
+ if (ob->type == OB_ARMATURE) {
+ /* this happens for reading old files and to match library armatures
+ * with poses we do it ahead of BKE_object_where_is_calc to ensure animation
+ * is evaluated on the rebuilt pose, otherwise we get incorrect poses
+ * on file load */
+ if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC))
+ BKE_pose_rebuild(ob, ob->data);
}
-
- /* XXX new animsys warning: depsgraph tag OB_RECALC_DATA should not skip drivers,
- * which is only in BKE_object_where_is_calc now */
- /* XXX: should this case be OB_RECALC_OB instead? */
- if (ob->recalc & OB_RECALC_ALL) {
-
- if (G.debug & G_DEBUG_DEPSGRAPH)
- printf("recalcob %s\n", ob->id.name + 2);
-
- /* handle proxy copy for target */
- if (ID_IS_LINKED(ob) && ob->proxy_from) {
- // printf("ob proxy copy, lib ob %s proxy %s\n", ob->id.name, ob->proxy_from->id.name);
- if (ob->proxy_from->proxy_group) { /* transform proxy into group space */
- Object *obg = ob->proxy_from->proxy_group;
- float imat[4][4];
- invert_m4_m4(imat, obg->obmat);
- mul_m4_m4m4(ob->obmat, imat, ob->proxy_from->obmat);
- if (obg->dup_group) { /* should always be true */
- add_v3_v3(ob->obmat[3], obg->dup_group->dupli_ofs);
- }
- }
- else
- copy_m4_m4(ob->obmat, ob->proxy_from->obmat);
- }
- else
- BKE_object_where_is_calc_ex(eval_ctx, scene, rbw, ob, NULL);
+ }
+ /* XXX new animsys warning: depsgraph tag OB_RECALC_DATA should not skip drivers,
+ * which is only in BKE_object_where_is_calc now */
+ /* XXX: should this case be OB_RECALC_OB instead? */
+ if (recalc_object || recalc_data) {
+ if (G.debug & G_DEBUG_DEPSGRAPH) {
+ printf("recalcob %s\n", ob->id.name + 2);
}
-
- if (ob->recalc & OB_RECALC_DATA) {
- BKE_object_handle_data_update(eval_ctx, scene, ob);
+ /* Handle proxy copy for target. */
+ if (!BKE_object_eval_proxy_copy(eval_ctx, ob)) {
+ BKE_object_where_is_calc_ex(eval_ctx, scene, rbw, ob, NULL);
}
+ }
- ob->recalc &= ~OB_RECALC_ALL;
+ if (recalc_data) {
+ BKE_object_handle_data_update(eval_ctx, scene, ob);
}
- /* the case when this is a group proxy, object_update is called in group.c */
- if (ob->proxy) {
- /* set pointer in library proxy target, for copying, but restore it */
- ob->proxy->proxy_from = ob;
- // printf("set proxy pointer for later group stuff %s\n", ob->id.name);
+ ob->id.tag &= ~LIB_TAG_ID_RECALC_ALL;
- /* the no-group proxy case, we call update */
- if (ob->proxy_group == NULL) {
- if (do_proxy_update) {
- // printf("call update, lib ob %s proxy %s\n", ob->proxy->id.name, ob->id.name);
- BKE_object_handle_update(eval_ctx, scene, ob->proxy);
- }
- }
- }
+ object_handle_update_proxy(eval_ctx, scene, ob, do_proxy_update);
}
+
/* WARNING: "scene" here may not be the scene object actually resides in.
* When dealing with background-sets, "scene" is actually the active scene.
* e.g. "scene" <-- set 1 <-- set 2 ("ob" lives here) <-- set 3 <-- ... <-- set n
@@ -3722,7 +3721,8 @@ bool BKE_object_modifier_update_subframe(
}
/* was originally OB_RECALC_ALL - TODO - which flags are really needed??? */
- ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME;
+ /* TODO(sergey): What about animation? */
+ ob->id.tag |= LIB_TAG_ID_RECALC_ALL;
BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, frame, ADT_RECALC_ANIM);
if (update_mesh) {
/* ignore cache clear during subframe updates
diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c
index 85635cb7d77..a16acd9d564 100644
--- a/source/blender/blenkernel/intern/object_dupli.c
+++ b/source/blender/blenkernel/intern/object_dupli.c
@@ -50,8 +50,9 @@
#include "BKE_animsys.h"
#include "BKE_DerivedMesh.h"
#include "BKE_font.h"
-#include "BKE_group.h"
#include "BKE_global.h"
+#include "BKE_group.h"
+#include "BKE_idprop.h"
#include "BKE_lattice.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
@@ -143,7 +144,8 @@ static void copy_dupli_context(DupliContext *r_ctx, const DupliContext *ctx, Obj
*/
static DupliObject *make_dupli(const DupliContext *ctx,
Object *ob, float mat[4][4], int index,
- bool animated, bool hide)
+ bool animated, bool hide,
+ IDProperty *collection_properties)
{
DupliObject *dob;
int i;
@@ -198,6 +200,10 @@ static DupliObject *make_dupli(const DupliContext *ctx,
dob->random_id ^= BLI_hash_int(BLI_hash_string(ctx->object->id.name + 2));
}
+ if (collection_properties) {
+ dob->collection_properties = IDP_CopyProperty(collection_properties);
+ }
+
return dob;
}
@@ -238,23 +244,23 @@ static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChild
Object *obedit = ctx->scene->obedit;
if (ctx->group) {
- unsigned int lay = ctx->group->layer;
int groupid = 0;
- GroupObject *go;
- for (go = ctx->group->gobject.first; go; go = go->next, groupid++) {
- Object *ob = go->ob;
-
- if ((ob->lay & lay) && ob != obedit && is_child(ob, parent)) {
+ FOREACH_GROUP_BASE(ctx->group, base)
+ {
+ Object *ob = base->object;
+ if ((base->flag & BASE_VISIBLED) && ob != obedit && is_child(ob, parent)) {
DupliContext pctx;
copy_dupli_context(&pctx, ctx, ctx->object, NULL, groupid, false);
/* mballs have a different dupli handling */
- if (ob->type != OB_MBALL)
+ if (ob->type != OB_MBALL) {
ob->flag |= OB_DONE; /* doesnt render */
-
+ }
make_child_duplis_cb(&pctx, userdata, ob);
}
+ groupid++;
}
+ FOREACH_GROUP_BASE_END
}
else {
int baseid = 0;
@@ -281,13 +287,12 @@ static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChild
/* OB_DUPLIGROUP */
static void make_duplis_group(const DupliContext *ctx)
{
- bool for_render = (ctx->eval_ctx->mode == DAG_EVAL_RENDER);
Object *ob = ctx->object;
Group *group;
- GroupObject *go;
+ Base *base;
float group_mat[4][4];
int id;
- bool animated, hide;
+ bool animated;
if (ob->dup_group == NULL) return;
group = ob->dup_group;
@@ -309,34 +314,18 @@ static void make_duplis_group(const DupliContext *ctx)
animated = BKE_group_is_animated(group, ob);
- for (go = group->gobject.first, id = 0; go; go = go->next, id++) {
- /* note, if you check on layer here, render goes wrong... it still deforms verts and uses parent imat */
- if (go->ob != ob) {
+ for (base = group->view_layer->object_bases.first, id = 0; base; base = base->next, id++) {
+ if (base->object != ob && (base->flag & BASE_VISIBLED)) {
float mat[4][4];
- /* Special case for instancing dupli-groups, see: T40051
- * this object may be instanced via dupli-verts/faces, in this case we don't want to render
- * (blender convention), but _do_ show in the viewport.
- *
- * Regular objects work fine but not if we're instancing dupli-groups,
- * because the rules for rendering aren't applied to objects they instance.
- * We could recursively pass down the 'hide' flag instead, but that seems unnecessary.
- */
- if (for_render && go->ob->parent && go->ob->parent->transflag & (OB_DUPLIVERTS | OB_DUPLIFACES)) {
- continue;
- }
-
/* group dupli offset, should apply after everything else */
- mul_m4_m4m4(mat, group_mat, go->ob->obmat);
+ mul_m4_m4m4(mat, group_mat, base->object->obmat);
- /* check the group instance and object layers match, also that the object visible flags are ok. */
- hide = (go->ob->lay & group->layer) == 0 ||
- (for_render ? go->ob->restrictflag & OB_RESTRICT_RENDER : go->ob->restrictflag & OB_RESTRICT_VIEW);
-
- make_dupli(ctx, go->ob, mat, id, animated, hide);
+ BLI_assert(base->collection_properties != NULL);
+ make_dupli(ctx, base->object, mat, id, animated, false, base->collection_properties);
/* recursion */
- make_recursive_duplis(ctx, go->ob, group_mat, id, animated);
+ make_recursive_duplis(ctx, base->object, group_mat, id, animated);
}
}
}
@@ -399,7 +388,7 @@ static void make_duplis_frames(const DupliContext *ctx)
BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM); /* ob-eval will do drivers, so we don't need to do them */
BKE_object_where_is_calc_time(ctx->eval_ctx, scene, ob, (float)scene->r.cfra);
- make_dupli(ctx, ob, ob->obmat, scene->r.cfra, false, false);
+ make_dupli(ctx, ob, ob->obmat, scene->r.cfra, false, false, NULL);
}
}
@@ -484,7 +473,7 @@ static void vertex_dupli__mapFunc(void *userData, int index, const float co[3],
*/
mul_m4_m4m4(space_mat, obmat, inst_ob->imat);
- dob = make_dupli(vdd->ctx, vdd->inst_ob, obmat, index, false, false);
+ dob = make_dupli(vdd->ctx, vdd->inst_ob, obmat, index, false, false, NULL);
if (vdd->orco)
copy_v3_v3(dob->orco, vdd->orco[index]);
@@ -669,7 +658,7 @@ static void make_duplis_font(const DupliContext *ctx)
copy_v3_v3(obmat[3], vec);
- make_dupli(ctx, ob, obmat, a, false, false);
+ make_dupli(ctx, ob, obmat, a, false, false, NULL);
}
}
@@ -775,7 +764,7 @@ static void make_child_duplis_faces(const DupliContext *ctx, void *userdata, Obj
*/
mul_m4_m4m4(space_mat, obmat, inst_ob->imat);
- dob = make_dupli(ctx, inst_ob, obmat, a, false, false);
+ dob = make_dupli(ctx, inst_ob, obmat, a, false, false, NULL);
if (use_texcoords) {
float w = 1.0f / (float)mp->totloop;
@@ -858,7 +847,6 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
bool for_render = ctx->eval_ctx->mode == DAG_EVAL_RENDER;
bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW);
- GroupObject *go;
Object *ob = NULL, **oblist = NULL, obcopy, *obcopylist = NULL;
DupliObject *dob;
ParticleDupliWeight *dw;
@@ -912,10 +900,10 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
return;
}
else { /*PART_DRAW_GR */
- if (part->dup_group == NULL || BLI_listbase_is_empty(&part->dup_group->gobject))
+ if (part->dup_group == NULL || BLI_listbase_is_empty(&part->dup_group->view_layer->object_bases))
return;
- if (BLI_findptr(&part->dup_group->gobject, par, offsetof(GroupObject, ob))) {
+ if (BLI_findptr(&part->dup_group->view_layer->object_bases, par, offsetof(Base, object))) {
return;
}
}
@@ -947,8 +935,12 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
totgroup += dw->count;
}
else {
- for (go = part->dup_group->gobject.first; go; go = go->next)
+ FOREACH_GROUP_OBJECT(part->dup_group, object)
+ {
+ (void) object;
totgroup++;
+ }
+ FOREACH_GROUP_OBJECT_END
}
/* we also copy the actual objects to restore afterwards, since
@@ -967,11 +959,18 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
}
}
else {
- go = part->dup_group->gobject.first;
- for (a = 0; a < totgroup; a++, go = go->next) {
- oblist[a] = go->ob;
- obcopylist[a] = *go->ob;
+ a = 0;
+ FOREACH_GROUP_OBJECT(part->dup_group, object)
+ {
+ oblist[a] = object;
+ obcopylist[a] = *object;
+ a++;
+
+ if (a >= totgroup) {
+ continue;
+ }
}
+ FOREACH_GROUP_OBJECT_END
}
}
else {
@@ -1060,23 +1059,33 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
}
if (part->ren_as == PART_DRAW_GR && psys->part->draw & PART_DRAW_WHOLE_GR) {
- for (go = part->dup_group->gobject.first, b = 0; go; go = go->next, b++) {
-
+ b = 0;
+ FOREACH_GROUP_OBJECT(part->dup_group, object)
+ {
copy_m4_m4(tmat, oblist[b]->obmat);
+
/* apply particle scale */
mul_mat3_m4_fl(tmat, size * scale);
mul_v3_fl(tmat[3], size * scale);
+
/* group dupli offset, should apply after everything else */
- if (!is_zero_v3(part->dup_group->dupli_ofs))
+ if (!is_zero_v3(part->dup_group->dupli_ofs)) {
sub_v3_v3(tmat[3], part->dup_group->dupli_ofs);
+ }
+
/* individual particle transform */
mul_m4_m4m4(mat, pamat, tmat);
- dob = make_dupli(ctx, go->ob, mat, a, false, false);
+ dob = make_dupli(ctx, object, mat, a, false, false, NULL);
dob->particle_system = psys;
- if (use_texcoords)
+
+ if (use_texcoords) {
psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco);
+ }
+
+ b++;
}
+ FOREACH_GROUP_OBJECT_END
}
else {
/* to give ipos in object correct offset */
@@ -1121,7 +1130,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
if (part->draw & PART_DRAW_GLOBAL_OB)
add_v3_v3v3(mat[3], mat[3], vec);
- dob = make_dupli(ctx, ob, mat, a, false, false);
+ dob = make_dupli(ctx, ob, mat, a, false, false, NULL);
dob->particle_system = psys;
if (use_texcoords)
psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco);
@@ -1238,6 +1247,14 @@ ListBase *object_duplilist(const EvaluationContext *eval_ctx, Scene *sce, Object
void free_object_duplilist(ListBase *lb)
{
+
+ for (DupliObject *dob = lb->first; dob; dob = dob->next) {
+ if (dob->collection_properties) {
+ IDP_FreeProperty(dob->collection_properties);
+ MEM_freeN(dob->collection_properties);
+ }
+ }
+
BLI_freelistN(lb);
MEM_freeN(lb);
}
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index 1e8de416ea9..71d8c1981af 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -68,7 +68,6 @@
#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf
void BKE_object_eval_local_transform(const EvaluationContext *UNUSED(eval_ctx),
- Scene *UNUSED(scene),
Object *ob)
{
DEBUG_PRINT("%s on %s (%p)\n", __func__, ob->id.name, ob);
@@ -273,34 +272,33 @@ void BKE_object_handle_data_update(
/* quick cache removed */
}
-void BKE_object_eval_uber_transform(const EvaluationContext *UNUSED(eval_ctx),
- Scene *UNUSED(scene),
- Object *ob)
+bool BKE_object_eval_proxy_copy(const EvaluationContext *UNUSED(eval_ctx),
+ Object *object)
{
- /* TODO(sergey): Currently it's a duplicate of logic in BKE_object_handle_update_ex(). */
- // XXX: it's almost redundant now...
-
/* Handle proxy copy for target, */
- if (ID_IS_LINKED(ob) && ob->proxy_from) {
- if (ob->proxy_from->proxy_group) {
+ if (ID_IS_LINKED(object) && object->proxy_from) {
+ if (object->proxy_from->proxy_group) {
/* Transform proxy into group space. */
- Object *obg = ob->proxy_from->proxy_group;
+ Object *obg = object->proxy_from->proxy_group;
float imat[4][4];
invert_m4_m4(imat, obg->obmat);
- mul_m4_m4m4(ob->obmat, imat, ob->proxy_from->obmat);
+ mul_m4_m4m4(object->obmat, imat, object->proxy_from->obmat);
/* Should always be true. */
if (obg->dup_group) {
- add_v3_v3(ob->obmat[3], obg->dup_group->dupli_ofs);
+ add_v3_v3(object->obmat[3], obg->dup_group->dupli_ofs);
}
}
- else
- copy_m4_m4(ob->obmat, ob->proxy_from->obmat);
+ else {
+ copy_m4_m4(object->obmat, object->proxy_from->obmat);
+ }
+ return true;
}
+ return false;
+}
- ob->recalc &= ~(OB_RECALC_OB | OB_RECALC_TIME);
- if (ob->data == NULL) {
- ob->recalc &= ~OB_RECALC_DATA;
- }
+void BKE_object_eval_uber_transform(const EvaluationContext *eval_ctx, Object *object)
+{
+ BKE_object_eval_proxy_copy(eval_ctx, object);
}
void BKE_object_eval_uber_data(const EvaluationContext *eval_ctx,
@@ -379,8 +377,6 @@ void BKE_object_eval_uber_data(const EvaluationContext *eval_ctx,
#endif
}
}
-
- ob->recalc &= ~(OB_RECALC_DATA | OB_RECALC_TIME);
}
void BKE_object_eval_cloth(const EvaluationContext *UNUSED(eval_ctx),
@@ -391,6 +387,22 @@ void BKE_object_eval_cloth(const EvaluationContext *UNUSED(eval_ctx),
BKE_ptcache_object_reset(scene, object, PTCACHE_RESET_DEPSGRAPH);
}
+void BKE_object_eval_transform_all(const EvaluationContext *eval_ctx,
+ Scene *scene,
+ Object *object)
+{
+ /* This mimics full transform update chain from new depsgraph. */
+ BKE_object_eval_local_transform(eval_ctx, object);
+ if (object->parent != NULL) {
+ BKE_object_eval_parent(eval_ctx, scene, object);
+ }
+ if (!BLI_listbase_is_empty(&object->constraints)) {
+ BKE_object_eval_constraints(eval_ctx, scene, object);
+ }
+ BKE_object_eval_uber_transform(eval_ctx, object);
+ BKE_object_eval_done(eval_ctx, object);
+}
+
void BKE_object_eval_update_shading(const EvaluationContext *UNUSED(eval_ctx),
Object *object)
{
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 209c7398d38..7d1c80dca41 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -327,18 +327,17 @@ bool psys_check_edited(ParticleSystem *psys)
void psys_check_group_weights(ParticleSettings *part)
{
ParticleDupliWeight *dw, *tdw;
- GroupObject *go;
int current = 0;
- if (part->ren_as == PART_DRAW_GR && part->dup_group && part->dup_group->gobject.first) {
+ if (part->ren_as == PART_DRAW_GR && part->dup_group && part->dup_group->view_layer->object_bases.first) {
/* First try to find NULL objects from their index,
* and remove all weights that don't have an object in the group. */
dw = part->dupliweights.first;
while (dw) {
if (dw->ob == NULL || !BKE_group_object_exists(part->dup_group, dw->ob)) {
- go = (GroupObject *)BLI_findlink(&part->dup_group->gobject, dw->index);
- if (go) {
- dw->ob = go->ob;
+ Base *base = BLI_findlink(&part->dup_group->view_layer->object_bases, dw->index);
+ if (base != NULL) {
+ dw->ob = base->object;
}
else {
tdw = dw->next;
@@ -352,21 +351,21 @@ void psys_check_group_weights(ParticleSettings *part)
}
/* then add objects in the group to new list */
- go = part->dup_group->gobject.first;
- while (go) {
+ FOREACH_GROUP_OBJECT(part->dup_group, object)
+ {
dw = part->dupliweights.first;
- while (dw && dw->ob != go->ob)
+ while (dw && dw->ob != object) {
dw = dw->next;
-
+ }
+
if (!dw) {
dw = MEM_callocN(sizeof(ParticleDupliWeight), "ParticleDupliWeight");
- dw->ob = go->ob;
+ dw->ob = object;
dw->count = 1;
BLI_addtail(&part->dupliweights, dw);
}
-
- go = go->next;
}
+ FOREACH_GROUP_OBJECT_END
dw = part->dupliweights.first;
for (; dw; dw = dw->next) {
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index f75b14579c7..bd4b817c8cd 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -57,6 +57,7 @@
#include "BKE_cdderivedmesh.h"
#include "BKE_effect.h"
#include "BKE_global.h"
+#include "BKE_group.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_mesh.h"
@@ -90,26 +91,30 @@ void BKE_rigidbody_free_world(RigidBodyWorld *rbw)
if (rbw->physics_world) {
/* free physics references, we assume that all physics objects in will have been added to the world */
- GroupObject *go;
if (rbw->constraints) {
- for (go = rbw->constraints->gobject.first; go; go = go->next) {
- if (go->ob && go->ob->rigidbody_constraint) {
- RigidBodyCon *rbc = go->ob->rigidbody_constraint;
-
- if (rbc->physics_constraint)
+ FOREACH_GROUP_OBJECT(rbw->constraints, object)
+ {
+ if (object->rigidbody_constraint) {
+ RigidBodyCon *rbc = object->rigidbody_constraint;
+ if (rbc->physics_constraint) {
RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint);
+ }
}
}
+ FOREACH_GROUP_OBJECT_END
}
- if (rbw->group) {
- for (go = rbw->group->gobject.first; go; go = go->next) {
- if (go->ob && go->ob->rigidbody_object) {
- RigidBodyOb *rbo = go->ob->rigidbody_object;
- if (rbo->physics_object)
+ if (rbw->group) {
+ FOREACH_GROUP_OBJECT(rbw->group, object)
+ {
+ if (object->rigidbody_object) {
+ RigidBodyOb *rbo = object->rigidbody_object;
+ if (rbo->physics_object) {
RB_dworld_remove_body(rbw->physics_world, rbo->physics_object);
+ }
}
}
+ FOREACH_GROUP_OBJECT_END
}
/* free dynamics world */
RB_dworld_delete(rbw->physics_world);
@@ -1124,7 +1129,6 @@ void BKE_rigidbody_remove_object(Scene *scene, Object *ob)
RigidBodyWorld *rbw = scene->rigidbody_world;
RigidBodyOb *rbo = ob->rigidbody_object;
RigidBodyCon *rbc;
- GroupObject *go;
int i;
if (rbw) {
@@ -1144,8 +1148,8 @@ void BKE_rigidbody_remove_object(Scene *scene, Object *ob)
/* remove object from rigid body constraints */
if (rbw->constraints) {
- for (go = rbw->constraints->gobject.first; go; go = go->next) {
- Object *obt = go->ob;
+ FOREACH_GROUP_OBJECT(rbw->constraints, obt)
+ {
if (obt && obt->rigidbody_constraint) {
rbc = obt->rigidbody_constraint;
if (ELEM(ob, rbc->ob1, rbc->ob2)) {
@@ -1153,6 +1157,7 @@ void BKE_rigidbody_remove_object(Scene *scene, Object *ob)
}
}
}
+ FOREACH_GROUP_OBJECT_END
}
}
@@ -1186,20 +1191,22 @@ void BKE_rigidbody_remove_constraint(Scene *scene, Object *ob)
/* Update object array and rigid body count so they're in sync with the rigid body group */
static void rigidbody_update_ob_array(RigidBodyWorld *rbw)
{
- GroupObject *go;
int i, n;
- n = BLI_listbase_count(&rbw->group->gobject);
+ n = BLI_listbase_count(&rbw->group->view_layer->object_bases);
if (rbw->numbodies != n) {
rbw->numbodies = n;
rbw->objects = realloc(rbw->objects, sizeof(Object *) * rbw->numbodies);
}
- for (go = rbw->group->gobject.first, i = 0; go; go = go->next, i++) {
- Object *ob = go->ob;
- rbw->objects[i] = ob;
+ i = 0;
+ FOREACH_GROUP_OBJECT(rbw->group, object)
+ {
+ rbw->objects[i] = object;
+ i++;
}
+ FOREACH_GROUP_OBJECT_END
}
static void rigidbody_update_sim_world(Scene *scene, RigidBodyWorld *rbw)
@@ -1313,8 +1320,6 @@ static void rigidbody_update_sim_ob(const struct EvaluationContext *eval_ctx, Sc
*/
static void rigidbody_update_simulation(const struct EvaluationContext *eval_ctx, Scene *scene, RigidBodyWorld *rbw, bool rebuild)
{
- GroupObject *go;
-
/* update world */
if (rebuild)
BKE_rigidbody_validate_sim_world(scene, rbw, true);
@@ -1327,24 +1332,22 @@ static void rigidbody_update_simulation(const struct EvaluationContext *eval_ctx
* Memory management needs redesign here, this is just a dirty workaround.
*/
if (rebuild && rbw->constraints) {
- for (go = rbw->constraints->gobject.first; go; go = go->next) {
- Object *ob = go->ob;
- if (ob) {
- RigidBodyCon *rbc = ob->rigidbody_constraint;
- if (rbc && rbc->physics_constraint) {
- RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint);
- RB_constraint_delete(rbc->physics_constraint);
- rbc->physics_constraint = NULL;
- }
+ FOREACH_GROUP_OBJECT(rbw->constraints, ob)
+ {
+ RigidBodyCon *rbc = ob->rigidbody_constraint;
+ if (rbc && rbc->physics_constraint) {
+ RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint);
+ RB_constraint_delete(rbc->physics_constraint);
+ rbc->physics_constraint = NULL;
}
}
+ FOREACH_GROUP_OBJECT_END
}
/* update objects */
- for (go = rbw->group->gobject.first; go; go = go->next) {
- Object *ob = go->ob;
-
- if (ob && ob->type == OB_MESH) {
+ FOREACH_GROUP_OBJECT(rbw->group, ob)
+ {
+ if (ob->type == OB_MESH) {
/* validate that we've got valid object set up here... */
RigidBodyOb *rbo = ob->rigidbody_object;
/* update transformation matrix of the object so we don't get a frame of lag for simple animations */
@@ -1385,62 +1388,59 @@ static void rigidbody_update_simulation(const struct EvaluationContext *eval_ctx
rigidbody_update_sim_ob(eval_ctx, scene, rbw, ob, rbo);
}
}
+ FOREACH_GROUP_OBJECT_END
/* update constraints */
if (rbw->constraints == NULL) /* no constraints, move on */
return;
- for (go = rbw->constraints->gobject.first; go; go = go->next) {
- Object *ob = go->ob;
- if (ob) {
- /* validate that we've got valid object set up here... */
- RigidBodyCon *rbc = ob->rigidbody_constraint;
- /* update transformation matrix of the object so we don't get a frame of lag for simple animations */
- BKE_object_where_is_calc(eval_ctx, scene, ob);
+ FOREACH_GROUP_OBJECT(rbw->constraints, ob)
+ {
+ /* validate that we've got valid object set up here... */
+ RigidBodyCon *rbc = ob->rigidbody_constraint;
+ /* update transformation matrix of the object so we don't get a frame of lag for simple animations */
+ BKE_object_where_is_calc(eval_ctx, scene, ob);
- if (rbc == NULL) {
- /* Since this object is included in the group but doesn't have
- * constraint settings (perhaps it was added manually), add!
- */
- ob->rigidbody_constraint = BKE_rigidbody_create_constraint(scene, ob, RBC_TYPE_FIXED);
- rigidbody_validate_sim_constraint(rbw, ob, true);
+ if (rbc == NULL) {
+ /* Since this object is included in the group but doesn't have
+ * constraint settings (perhaps it was added manually), add!
+ */
+ ob->rigidbody_constraint = BKE_rigidbody_create_constraint(scene, ob, RBC_TYPE_FIXED);
+ rigidbody_validate_sim_constraint(rbw, ob, true);
- rbc = ob->rigidbody_constraint;
+ rbc = ob->rigidbody_constraint;
+ }
+ else {
+ /* perform simulation data updates as tagged */
+ if (rebuild) {
+ /* World has been rebuilt so rebuild constraint */
+ rigidbody_validate_sim_constraint(rbw, ob, true);
}
- else {
- /* perform simulation data updates as tagged */
- if (rebuild) {
- /* World has been rebuilt so rebuild constraint */
- rigidbody_validate_sim_constraint(rbw, ob, true);
- }
- else if (rbc->flag & RBC_FLAG_NEEDS_VALIDATE) {
- rigidbody_validate_sim_constraint(rbw, ob, false);
- }
- rbc->flag &= ~RBC_FLAG_NEEDS_VALIDATE;
+ else if (rbc->flag & RBC_FLAG_NEEDS_VALIDATE) {
+ rigidbody_validate_sim_constraint(rbw, ob, false);
}
+ rbc->flag &= ~RBC_FLAG_NEEDS_VALIDATE;
}
}
+ FOREACH_GROUP_OBJECT_END
}
static void rigidbody_update_simulation_post_step(RigidBodyWorld *rbw)
{
- GroupObject *go;
-
- for (go = rbw->group->gobject.first; go; go = go->next) {
- Object *ob = go->ob;
-
- if (ob) {
- RigidBodyOb *rbo = ob->rigidbody_object;
- /* reset kinematic state for transformed objects */
- if (rbo && (ob->flag & SELECT) && (G.moving & G_TRANSFORM_OBJ)) {
- RB_body_set_kinematic_state(rbo->physics_object, rbo->flag & RBO_FLAG_KINEMATIC || rbo->flag & RBO_FLAG_DISABLED);
- RB_body_set_mass(rbo->physics_object, RBO_GET_MASS(rbo));
- /* deactivate passive objects so they don't interfere with deactivation of active objects */
- if (rbo->type == RBO_TYPE_PASSIVE)
- RB_body_deactivate(rbo->physics_object);
- }
+ FOREACH_GROUP_BASE(rbw->group, base)
+ {
+ Object *ob = base->object;
+ RigidBodyOb *rbo = ob->rigidbody_object;
+ /* Reset kinematic state for transformed objects. */
+ if (rbo && (base->flag & BASE_SELECTED) && (G.moving & G_TRANSFORM_OBJ)) {
+ RB_body_set_kinematic_state(rbo->physics_object, rbo->flag & RBO_FLAG_KINEMATIC || rbo->flag & RBO_FLAG_DISABLED);
+ RB_body_set_mass(rbo->physics_object, RBO_GET_MASS(rbo));
+ /* Deactivate passive objects so they don't interfere with deactivation of active objects. */
+ if (rbo->type == RBO_TYPE_PASSIVE)
+ RB_body_deactivate(rbo->physics_object);
}
}
+ FOREACH_GROUP_BASE_END
}
bool BKE_rigidbody_check_sim_running(RigidBodyWorld *rbw, float ctime)
@@ -1567,7 +1567,7 @@ void BKE_rigidbody_rebuild_world(const struct EvaluationContext *eval_ctx, Scene
cache = rbw->pointcache;
/* flag cache as outdated if we don't have a world or number of objects in the simulation has changed */
- if (rbw->physics_world == NULL || rbw->numbodies != BLI_listbase_count(&rbw->group->gobject)) {
+ if (rbw->physics_world == NULL || rbw->numbodies != BLI_listbase_count(&rbw->group->view_layer->object_bases)) {
cache->flag |= PTCACHE_OUTDATED;
}
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 7fa7aa71eae..c095236733f 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -151,79 +151,6 @@ static void remove_sequencer_fcurves(Scene *sce)
}
}
-/* copy SceneCollection tree but keep pointing to the same objects */
-static void scene_collection_copy(SceneCollection *sc_dst, SceneCollection *sc_src, const int flag)
-{
- BLI_duplicatelist(&sc_dst->objects, &sc_src->objects);
- if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- for (LinkData *link = sc_dst->objects.first; link; link = link->next) {
- id_us_plus(link->data);
- }
- }
-
- BLI_duplicatelist(&sc_dst->filter_objects, &sc_src->filter_objects);
- if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- for (LinkData *link = sc_dst->filter_objects.first; link; link = link->next) {
- id_us_plus(link->data);
- }
- }
-
- BLI_duplicatelist(&sc_dst->scene_collections, &sc_src->scene_collections);
- for (SceneCollection *nsc_src = sc_src->scene_collections.first, *nsc_dst = sc_dst->scene_collections.first;
- nsc_src;
- nsc_src = nsc_src->next, nsc_dst = nsc_dst->next)
- {
- scene_collection_copy(nsc_dst, nsc_src, flag);
- }
-}
-
-/* Find the equivalent SceneCollection in the new tree */
-static SceneCollection *scene_collection_from_new_tree(SceneCollection *sc_reference, SceneCollection *sc_dst, SceneCollection *sc_src)
-{
- if (sc_src == sc_reference) {
- return sc_dst;
- }
-
- for (SceneCollection *nsc_src = sc_src->scene_collections.first, *nsc_dst = sc_dst->scene_collections.first;
- nsc_src;
- nsc_src = nsc_src->next, nsc_dst = nsc_dst->next)
- {
- SceneCollection *found = scene_collection_from_new_tree(sc_reference, nsc_dst, nsc_src);
- if (found != NULL) {
- return found;
- }
- }
- return NULL;
-}
-
-static void layer_collections_sync_flags(ListBase *layer_collections_dst, const ListBase *layer_collections_src)
-{
- LayerCollection *layer_collection_dst = (LayerCollection *)layer_collections_dst->first;
- const LayerCollection *layer_collection_src = (const LayerCollection *)layer_collections_src->first;
- while (layer_collection_dst != NULL) {
- layer_collection_dst->flag = layer_collection_src->flag;
- layer_collections_sync_flags(&layer_collection_dst->layer_collections,
- &layer_collection_src->layer_collections);
- /* TODO(sergey/dfelinto): Overrides. */
- layer_collection_dst = layer_collection_dst->next;
- layer_collection_src = layer_collection_src->next;
- }
-}
-
-
-/* recreate the LayerCollection tree */
-static void layer_collections_recreate(
- ViewLayer *view_layer_dst, ListBase *lb_src, SceneCollection *mc_dst, SceneCollection *mc_src)
-{
- for (LayerCollection *lc_src = lb_src->first; lc_src; lc_src = lc_src->next) {
- SceneCollection *sc_dst = scene_collection_from_new_tree(lc_src->scene_collection, mc_dst, mc_src);
- BLI_assert(sc_dst);
-
- /* instead of synchronizing both trees we simply re-create it */
- BKE_collection_link(view_layer_dst, sc_dst);
- }
-}
-
/**
* Only copy internal data of Scene ID from source to already allocated/initialized destination.
* You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
@@ -244,11 +171,11 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons
/* layers and collections */
sce_dst->collection = MEM_dupallocN(sce_src->collection);
- SceneCollection *mc_src = BKE_collection_master(sce_src);
- SceneCollection *mc_dst = BKE_collection_master(sce_dst);
+ SceneCollection *mc_src = BKE_collection_master(&sce_src->id);
+ SceneCollection *mc_dst = BKE_collection_master(&sce_dst->id);
- /* recursively creates a new SceneCollection tree */
- scene_collection_copy(mc_dst, mc_src, flag_subdata);
+ /* Recursively creates a new SceneCollection tree. */
+ BKE_collection_copy_data(mc_dst, mc_src, flag_subdata);
IDPropertyTemplate val = {0};
BLI_duplicatelist(&sce_dst->view_layers, &sce_src->view_layers);
@@ -256,39 +183,7 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons
view_layer_src;
view_layer_src = view_layer_src->next, view_layer_dst = view_layer_dst->next)
{
- if (view_layer_dst->id_properties != NULL) {
- view_layer_dst->id_properties = IDP_CopyProperty_ex(view_layer_dst->id_properties, flag_subdata);
- }
- BKE_freestyle_config_copy(&view_layer_dst->freestyle_config, &view_layer_src->freestyle_config, flag_subdata);
-
- view_layer_dst->stats = NULL;
- view_layer_dst->properties_evaluated = NULL;
- view_layer_dst->properties = IDP_New(IDP_GROUP, &val, ROOT_PROP);
- IDP_MergeGroup_ex(view_layer_dst->properties, view_layer_src->properties, true, flag_subdata);
-
- /* we start fresh with no overrides and no visibility flags set
- * instead of syncing both trees we simply unlink and relink the scene collection */
- BLI_listbase_clear(&view_layer_dst->layer_collections);
- BLI_listbase_clear(&view_layer_dst->object_bases);
- BLI_listbase_clear(&view_layer_dst->drawdata);
-
- layer_collections_recreate(view_layer_dst, &view_layer_src->layer_collections, mc_dst, mc_src);
-
- /* Now we handle the syncing for visibility, selectability, ... */
- layer_collections_sync_flags(&view_layer_dst->layer_collections, &view_layer_src->layer_collections);
-
- Object *active_ob = OBACT(view_layer_src);
- for (Base *base_src = view_layer_src->object_bases.first, *base_dst = view_layer_dst->object_bases.first;
- base_src;
- base_src = base_src->next, base_dst = base_dst->next)
- {
- base_dst->flag = base_src->flag;
- base_dst->flag_legacy = base_src->flag_legacy;
-
- if (base_dst->object == active_ob) {
- view_layer_dst->basact = base_dst;
- }
- }
+ BKE_view_layer_copy_data(view_layer_dst, view_layer_src, mc_dst, mc_src, flag_subdata);
}
sce_dst->collection_properties = IDP_New(IDP_GROUP, &val, ROOT_PROP);
@@ -649,7 +544,7 @@ void BKE_scene_free_ex(Scene *sce, const bool do_id_user)
}
/* Master Collection */
- BKE_collection_master_free(sce, do_id_user);
+ BKE_collection_master_free(&sce->id, do_id_user);
MEM_freeN(sce->collection);
sce->collection = NULL;
@@ -1082,7 +977,6 @@ void BKE_scene_set_background(Main *bmain, Scene *scene)
{
Object *ob;
Group *group;
- GroupObject *go;
/* check for cyclic sets, for reading old files but also for definite security (py?) */
BKE_scene_validate_setscene(bmain, scene);
@@ -1097,11 +991,11 @@ void BKE_scene_set_background(Main *bmain, Scene *scene)
/* group flags again */
for (group = bmain->group.first; group; group = group->id.next) {
- for (go = group->gobject.first; go; go = go->next) {
- if (go->ob) {
- go->ob->flag |= OB_FROMGROUP;
- }
+ FOREACH_GROUP_OBJECT(group, object)
+ {
+ object->flag |= OB_FROMGROUP;
}
+ FOREACH_GROUP_OBJECT_END
}
/* copy layers and flags from bases to objects */
@@ -1541,7 +1435,7 @@ void BKE_scene_graph_update_tagged(EvaluationContext *eval_ctx,
/* Update sound system animation (TODO, move to depsgraph). */
BKE_sound_update_scene(bmain, scene);
/* Inform editors about possible changes. */
- DEG_ids_check_recalc(bmain, scene, false);
+ DEG_ids_check_recalc(bmain, scene, view_layer, false);
/* Clear recalc flags. */
DEG_ids_clear_recalc(bmain);
}
@@ -1562,11 +1456,7 @@ void BKE_scene_graph_update_for_newframe(EvaluationContext *eval_ctx,
* for example, clearing update tags from bmain.
*/
const float ctime = BKE_scene_frame_get(scene);
- /* Inform editors we are starting scene update. */
- DEG_editors_update_pre(bmain, scene, true);
- /* Keep this first.
- * TODO(sergey): Should it be after the editors update?
- */
+ /* Keep this first. */
BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_FRAME_CHANGE_PRE);
/* Update animated image textures for particles, modifiers, gpu, etc,
* call this at the start so modifiers with textures don't lag 1 frame.
@@ -1592,7 +1482,7 @@ void BKE_scene_graph_update_for_newframe(EvaluationContext *eval_ctx,
/* Notify editors and python about recalc. */
BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_FRAME_CHANGE_POST);
/* Inform editors about possible changes. */
- DEG_ids_check_recalc(bmain, scene, true);
+ DEG_ids_check_recalc(bmain, scene, view_layer, true);
/* clear recalc flags */
DEG_ids_clear_recalc(bmain);
}
@@ -2322,8 +2212,8 @@ Depsgraph *BKE_scene_get_depsgraph(Scene *scene,
Depsgraph **depsgraph_ptr;
if (!BLI_ghash_ensure_p_ex(scene->depsgraph_hash,
&key,
- (void***)&key_ptr,
- (void***)&depsgraph_ptr))
+ (void ***)&key_ptr,
+ (void ***)&depsgraph_ptr))
{
*key_ptr = MEM_mallocN(sizeof(DepsgraphKey), __func__);
**key_ptr = key;
diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c
index a2c45057bf7..ee80438db64 100644
--- a/source/blender/blenkernel/intern/seqeffects.c
+++ b/source/blender/blenkernel/intern/seqeffects.c
@@ -53,15 +53,18 @@
#include "IMB_imbuf.h"
#include "IMB_colormanagement.h"
+#include "BLI_math_color_blend.h"
+
#include "RNA_access.h"
#include "RE_pipeline.h"
#include "BLF_api.h"
-static void slice_get_byte_buffers(const SeqRenderData *context, const ImBuf *ibuf1, const ImBuf *ibuf2,
- const ImBuf *ibuf3, const ImBuf *out, int start_line, unsigned char **rect1,
- unsigned char **rect2, unsigned char **rect3, unsigned char **rect_out)
+static void slice_get_byte_buffers(
+ const SeqRenderData *context, const ImBuf *ibuf1, const ImBuf *ibuf2,
+ const ImBuf *ibuf3, const ImBuf *out, int start_line, unsigned char **rect1,
+ unsigned char **rect2, unsigned char **rect3, unsigned char **rect_out)
{
int offset = 4 * start_line * context->rectx;
@@ -75,9 +78,10 @@ static void slice_get_byte_buffers(const SeqRenderData *context, const ImBuf *ib
*rect3 = (unsigned char *)ibuf3->rect + offset;
}
-static void slice_get_float_buffers(const SeqRenderData *context, const ImBuf *ibuf1, const ImBuf *ibuf2,
- const ImBuf *ibuf3, const ImBuf *out, int start_line,
- float **rect1, float **rect2, float **rect3, float **rect_out)
+static void slice_get_float_buffers(
+ const SeqRenderData *context, const ImBuf *ibuf1, const ImBuf *ibuf2,
+ const ImBuf *ibuf3, const ImBuf *out, int start_line,
+ float **rect1, float **rect2, float **rect3, float **rect_out)
{
int offset = 4 * start_line * context->rectx;
@@ -171,7 +175,9 @@ static void init_alpha_over_or_under(Sequence *seq)
seq->seq1 = seq2;
}
-static void do_alphaover_effect_byte(float facf0, float facf1, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out)
+static void do_alphaover_effect_byte(
+ float facf0, float facf1, int x, int y,
+ unsigned char *rect1, unsigned char *rect2, unsigned char *out)
{
float fac2, mfac, fac, fac4;
int xo;
@@ -236,7 +242,9 @@ static void do_alphaover_effect_byte(float facf0, float facf1, int x, int y, un
}
}
-static void do_alphaover_effect_float(float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out)
+static void do_alphaover_effect_float(
+ float facf0, float facf1, int x, int y,
+ float *rect1, float *rect2, float *out)
{
float fac2, mfac, fac, fac4;
int xo;
@@ -299,9 +307,10 @@ static void do_alphaover_effect_float(float facf0, float facf1, int x, int y, f
}
}
-static void do_alphaover_effect(const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra), float facf0,
- float facf1, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3),
- int start_line, int total_lines, ImBuf *out)
+static void do_alphaover_effect(
+ const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra), float facf0,
+ float facf1, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3),
+ int start_line, int total_lines, ImBuf *out)
{
if (out->rect_float) {
float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
@@ -321,7 +330,9 @@ static void do_alphaover_effect(const SeqRenderData *context, Sequence *UNUSED(s
/*********************** Alpha Under *************************/
-static void do_alphaunder_effect_byte(float facf0, float facf1, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out)
+static void do_alphaunder_effect_byte(
+ float facf0, float facf1, int x, int y,
+ unsigned char *rect1, unsigned char *rect2, unsigned char *out)
{
float fac2, fac, fac4;
int xo;
@@ -393,7 +404,9 @@ static void do_alphaunder_effect_byte(float facf0, float facf1, int x, int y, un
}
}
-static void do_alphaunder_effect_float(float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out)
+static void do_alphaunder_effect_float(
+ float facf0, float facf1, int x, int y,
+ float *rect1, float *rect2, float *out)
{
float fac2, fac, fac4;
int xo;
@@ -467,9 +480,10 @@ static void do_alphaunder_effect_float(float facf0, float facf1, int x, int y,
}
}
-static void do_alphaunder_effect(const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra),
- float facf0, float facf1, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3),
- int start_line, int total_lines, ImBuf *out)
+static void do_alphaunder_effect(
+ const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra),
+ float facf0, float facf1, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3),
+ int start_line, int total_lines, ImBuf *out)
{
if (out->rect_float) {
float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
@@ -489,7 +503,9 @@ static void do_alphaunder_effect(const SeqRenderData *context, Sequence *UNUSED(
/*********************** Cross *************************/
-static void do_cross_effect_byte(float facf0, float facf1, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out)
+static void do_cross_effect_byte(
+ float facf0, float facf1, int x, int y,
+ unsigned char *rect1, unsigned char *rect2, unsigned char *out)
{
int fac1, fac2, fac3, fac4;
int xo;
@@ -577,9 +593,10 @@ static void do_cross_effect_float(float facf0, float facf1, int x, int y, float
}
}
-static void do_cross_effect(const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra),
- float facf0, float facf1, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3),
- int start_line, int total_lines, ImBuf *out)
+static void do_cross_effect(
+ const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra),
+ float facf0, float facf1, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3),
+ int start_line, int total_lines, ImBuf *out)
{
if (out->rect_float) {
float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
@@ -737,8 +754,9 @@ static void free_gammacross(Sequence *UNUSED(seq))
{
}
-static void do_gammacross_effect_byte(float facf0, float UNUSED(facf1), int x, int y, unsigned char *rect1,
- unsigned char *rect2, unsigned char *out)
+static void do_gammacross_effect_byte(
+ float facf0, float UNUSED(facf1), int x, int y, unsigned char *rect1,
+ unsigned char *rect2, unsigned char *out)
{
float fac1, fac2;
int xo;
@@ -788,8 +806,9 @@ static void do_gammacross_effect_byte(float facf0, float UNUSED(facf1), int x,
}
}
-static void do_gammacross_effect_float(float facf0, float UNUSED(facf1), int x, int y, float *rect1,
- float *rect2, float *out)
+static void do_gammacross_effect_float(
+ float facf0, float UNUSED(facf1), int x, int y, float *rect1,
+ float *rect2, float *out)
{
float fac1, fac2;
int xo;
@@ -831,9 +850,10 @@ static struct ImBuf *gammacross_init_execution(const SeqRenderData *context, ImB
return out;
}
-static void do_gammacross_effect(const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra),
- float facf0, float facf1, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3),
- int start_line, int total_lines, ImBuf *out)
+static void do_gammacross_effect(
+ const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra),
+ float facf0, float facf1, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3),
+ int start_line, int total_lines, ImBuf *out)
{
if (out->rect_float) {
float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
@@ -853,8 +873,9 @@ static void do_gammacross_effect(const SeqRenderData *context, Sequence *UNUSED(
/*********************** Add *************************/
-static void do_add_effect_byte(float facf0, float facf1, int x, int y, unsigned char *rect1, unsigned char *rect2,
- unsigned char *out)
+static void do_add_effect_byte(
+ float facf0, float facf1, int x, int y,
+ unsigned char *rect1, unsigned char *rect2, unsigned char *out)
{
int xo, fac1, fac3;
unsigned char *cp1, *cp2, *rt;
@@ -940,8 +961,9 @@ static void do_add_effect_float(float facf0, float facf1, int x, int y, float *r
}
}
-static void do_add_effect(const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra), float facf0, float facf1,
- ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), int start_line, int total_lines, ImBuf *out)
+static void do_add_effect(
+ const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra), float facf0, float facf1,
+ ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), int start_line, int total_lines, ImBuf *out)
{
if (out->rect_float) {
float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
@@ -961,7 +983,9 @@ static void do_add_effect(const SeqRenderData *context, Sequence *UNUSED(seq), f
/*********************** Sub *************************/
-static void do_sub_effect_byte(float facf0, float facf1, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out)
+static void do_sub_effect_byte(
+ float facf0, float facf1, int x, int y,
+ unsigned char *rect1, unsigned char *rect2, unsigned char *out)
{
int xo, fac1, fac3;
unsigned char *cp1, *cp2, *rt;
@@ -1003,7 +1027,9 @@ static void do_sub_effect_byte(float facf0, float facf1, int x, int y, unsigned
}
}
-static void do_sub_effect_float(float UNUSED(facf0), float facf1, int x, int y, float *rect1, float *rect2, float *out)
+static void do_sub_effect_float(
+ float UNUSED(facf0), float facf1, int x, int y,
+ float *rect1, float *rect2, float *out)
{
int xo;
float /* fac1, */ fac3_inv;
@@ -1047,8 +1073,9 @@ static void do_sub_effect_float(float UNUSED(facf0), float facf1, int x, int y,
}
}
-static void do_sub_effect(const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra), float facf0, float facf1,
- ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), int start_line, int total_lines, ImBuf *out)
+static void do_sub_effect(
+ const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra), float facf0, float facf1,
+ ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), int start_line, int total_lines, ImBuf *out)
{
if (out->rect_float) {
float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
@@ -1072,7 +1099,9 @@ static void do_sub_effect(const SeqRenderData *context, Sequence *UNUSED(seq), f
#define XOFF 8
#define YOFF 8
-static void do_drop_effect_byte(float facf0, float facf1, int x, int y, unsigned char *rect2i, unsigned char *rect1i, unsigned char *outi)
+static void do_drop_effect_byte(
+ float facf0, float facf1, int x, int y,
+ unsigned char *rect2i, unsigned char *rect1i, unsigned char *outi)
{
int temp, fac, fac1, fac2;
unsigned char *rt1, *rt2, *out;
@@ -1112,7 +1141,9 @@ static void do_drop_effect_byte(float facf0, float facf1, int x, int y, unsigned
memcpy(out, rt1, sizeof(*out) * yoff * 4 * width);
}
-static void do_drop_effect_float(float facf0, float facf1, int x, int y, float *rect2i, float *rect1i, float *outi)
+static void do_drop_effect_float(
+ float facf0, float facf1, int x, int y,
+ float *rect2i, float *rect1i, float *outi)
{
float temp, fac, fac1, fac2;
float *rt1, *rt2, *out;
@@ -1154,8 +1185,9 @@ static void do_drop_effect_float(float facf0, float facf1, int x, int y, float *
/*********************** Mul *************************/
-static void do_mul_effect_byte(float facf0, float facf1, int x, int y, unsigned char *rect1, unsigned char *rect2,
- unsigned char *out)
+static void do_mul_effect_byte(
+ float facf0, float facf1, int x, int y,
+ unsigned char *rect1, unsigned char *rect2, unsigned char *out)
{
int xo, fac1, fac3;
unsigned char *rt1, *rt2, *rt;
@@ -1202,7 +1234,9 @@ static void do_mul_effect_byte(float facf0, float facf1, int x, int y, unsigned
}
}
-static void do_mul_effect_float(float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out)
+static void do_mul_effect_float(
+ float facf0, float facf1, int x, int y,
+ float *rect1, float *rect2, float *out)
{
int xo;
float fac1, fac3;
@@ -1247,8 +1281,9 @@ static void do_mul_effect_float(float facf0, float facf1, int x, int y, float *r
}
}
-static void do_mul_effect(const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra), float facf0, float facf1,
- ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), int start_line, int total_lines, ImBuf *out)
+static void do_mul_effect(
+ const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra), float facf0, float facf1,
+ ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), int start_line, int total_lines, ImBuf *out)
{
if (out->rect_float) {
float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
@@ -1266,6 +1301,284 @@ static void do_mul_effect(const SeqRenderData *context, Sequence *UNUSED(seq), f
}
}
+/*********************** Blend Mode ***************************************/
+typedef void (*IMB_blend_func_byte)(unsigned char *dst, const unsigned char *src1, const unsigned char *src2);
+typedef void (*IMB_blend_func_float)(float *dst, const float *src1, const float *src2);
+
+BLI_INLINE void apply_blend_function_byte(
+ float facf0, float facf1, int x, int y,
+ unsigned char *rect1, unsigned char *rect2, unsigned char *out, IMB_blend_func_byte blend_function)
+{
+ int xo;
+ unsigned char *rt1, *rt2, *rt;
+ unsigned int achannel;
+ xo = x;
+ rt1 = rect1;
+ rt2 = rect2;
+ rt = out;
+ while (y--) {
+ for (x = xo; x > 0; x--) {
+ achannel = rt2[3];
+ rt2[3] = (unsigned int) achannel * facf0;
+ blend_function(rt, rt1, rt2);
+ rt2[3] = achannel;
+ rt[3] = rt2[3];
+ rt1 += 4;
+ rt2 += 4;
+ rt += 4;
+ }
+ if (y == 0) {
+ break;
+ }
+ y--;
+ for (x = xo; x > 0; x--) {
+ achannel = rt2[3];
+ rt2[3] = (unsigned int) achannel * facf1;
+ blend_function(rt, rt1, rt2);
+ rt2[3] = achannel;
+ rt[3] = rt2[3];
+ rt1 += 4;
+ rt2 += 4;
+ rt += 4;
+ }
+ }
+}
+
+BLI_INLINE void apply_blend_function_float(
+ float facf0, float facf1, int x, int y,
+ float *rect1, float *rect2, float *out, IMB_blend_func_float blend_function)
+{
+ int xo;
+ float *rt1, *rt2, *rt;
+ float achannel;
+ xo = x;
+ rt1 = rect1;
+ rt2 = rect2;
+ rt = out;
+ while (y--) {
+ for (x = xo; x > 0; x--) {
+ achannel = rt2[3];
+ rt2[3] = achannel * facf0;
+ blend_function(rt, rt1, rt2);
+ rt2[3] = achannel;
+ rt[3] = rt2[3];
+ rt1 += 4;
+ rt2 += 4;
+ rt += 4;
+ }
+ if (y == 0) {
+ break;
+ }
+ y--;
+ for (x = xo; x > 0; x--) {
+ achannel = rt2[3];
+ rt2[3] = achannel * facf1;
+ blend_function(rt, rt1, rt2);
+ rt2[3] = achannel;
+ rt[3] = rt2[3];
+ rt1 += 4;
+ rt2 += 4;
+ rt += 4;
+ }
+ }
+}
+
+static void do_blend_effect_float(
+ float facf0, float facf1, int x, int y,
+ float *rect1, float *rect2, int btype, float *out)
+{
+ switch (btype) {
+ case SEQ_TYPE_ADD:
+ apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_add_float);
+ break;
+ case SEQ_TYPE_SUB:
+ apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_sub_float);
+ break;
+ case SEQ_TYPE_MUL:
+ apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_mul_float);
+ break;
+ case SEQ_TYPE_DARKEN:
+ apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_darken_float);
+ break;
+ case SEQ_TYPE_BURN:
+ apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_burn_float);
+ break;
+ case SEQ_TYPE_LINEAR_BURN:
+ apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_linearburn_float);
+ break;
+ case SEQ_TYPE_SCREEN:
+ apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_screen_float);
+ break;
+ case SEQ_TYPE_LIGHTEN:
+ apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_lighten_float);
+ break;
+ case SEQ_TYPE_DODGE:
+ apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_dodge_float);
+ break;
+ case SEQ_TYPE_OVERLAY:
+ apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_overlay_float);
+ break;
+ case SEQ_TYPE_SOFT_LIGHT:
+ apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_softlight_float);
+ break;
+ case SEQ_TYPE_HARD_LIGHT:
+ apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_hardlight_float);
+ break;
+ case SEQ_TYPE_PIN_LIGHT:
+ apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_pinlight_float);
+ break;
+ case SEQ_TYPE_LIN_LIGHT:
+ apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_linearlight_float);
+ break;
+ case SEQ_TYPE_VIVID_LIGHT:
+ apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_vividlight_float);
+ break;
+ case SEQ_TYPE_BLEND_COLOR:
+ apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_color_float);
+ break;
+ case SEQ_TYPE_HUE:
+ apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_hue_float);
+ break;
+ case SEQ_TYPE_SATURATION:
+ apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_saturation_float);
+ break;
+ case SEQ_TYPE_VALUE:
+ apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_luminosity_float);
+ break;
+ case SEQ_TYPE_DIFFERENCE:
+ apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_difference_float);
+ break;
+ case SEQ_TYPE_EXCLUSION:
+ apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_exclusion_float);
+ break;
+ default:
+ break;
+ }
+}
+
+static void do_blend_effect_byte(
+ float facf0, float facf1, int x, int y,
+ unsigned char *rect1, unsigned char *rect2, int btype, unsigned char *out)
+{
+ switch (btype) {
+ case SEQ_TYPE_ADD:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_add_byte);
+ break;
+ case SEQ_TYPE_SUB:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_sub_byte);
+ break;
+ case SEQ_TYPE_MUL:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_mul_byte);
+ break;
+ case SEQ_TYPE_DARKEN:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_darken_byte);
+ break;
+ case SEQ_TYPE_BURN:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_burn_byte);
+ break;
+ case SEQ_TYPE_LINEAR_BURN:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_linearburn_byte);
+ break;
+ case SEQ_TYPE_SCREEN:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_screen_byte);
+ break;
+ case SEQ_TYPE_LIGHTEN:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_lighten_byte);
+ break;
+ case SEQ_TYPE_DODGE:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_dodge_byte);
+ break;
+ case SEQ_TYPE_OVERLAY:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_overlay_byte);
+ break;
+ case SEQ_TYPE_SOFT_LIGHT:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_softlight_byte);
+ break;
+ case SEQ_TYPE_HARD_LIGHT:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_hardlight_byte);
+ break;
+ case SEQ_TYPE_PIN_LIGHT:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_pinlight_byte);
+ break;
+ case SEQ_TYPE_LIN_LIGHT:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_linearlight_byte);
+ break;
+ case SEQ_TYPE_VIVID_LIGHT:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_vividlight_byte);
+ break;
+ case SEQ_TYPE_BLEND_COLOR:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_color_byte);
+ break;
+ case SEQ_TYPE_HUE:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_hue_byte);
+ break;
+ case SEQ_TYPE_SATURATION:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_saturation_byte);
+ break;
+ case SEQ_TYPE_VALUE:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_luminosity_byte);
+ break;
+ case SEQ_TYPE_DIFFERENCE:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_difference_byte);
+ break;
+ case SEQ_TYPE_EXCLUSION:
+ apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_exclusion_byte);
+ break;
+ default:
+ break;
+ }
+}
+
+static void do_blend_mode_effect(
+ const SeqRenderData *context, Sequence *seq, float UNUSED(cfra), float facf0, float facf1,
+ ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), int start_line, int total_lines, ImBuf *out)
+{
+ if (out->rect_float) {
+ float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
+ slice_get_float_buffers(context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
+ do_blend_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, seq->blend_mode, rect_out);
+ }
+ else {
+ unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
+ slice_get_byte_buffers(context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
+ do_blend_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, seq->blend_mode, rect_out);
+ }
+}
+/*********************** Color Mix Effect *************************/
+static void init_colormix_effect(Sequence *seq)
+{
+ ColorMixVars *data;
+
+ if (seq->effectdata) {
+ MEM_freeN(seq->effectdata);
+ }
+ seq->effectdata = MEM_callocN(sizeof(ColorMixVars), "colormixvars");
+ data = (ColorMixVars *) seq->effectdata;
+ data->blend_effect = SEQ_TYPE_OVERLAY;
+ data->factor = 1.0f;
+}
+
+static void do_colormix_effect(
+ const SeqRenderData *context, Sequence *seq, float UNUSED(cfra), float UNUSED(facf0), float UNUSED(facf1),
+ ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), int start_line, int total_lines, ImBuf *out)
+{
+ float facf;
+
+ ColorMixVars *data = seq->effectdata;
+ facf = data->factor;
+
+ if (out->rect_float) {
+ float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
+ slice_get_float_buffers(context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
+ do_blend_effect_float(facf, facf, context->rectx, total_lines, rect1, rect2, data->blend_effect, rect_out);
+ }
+ else {
+ unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
+ slice_get_byte_buffers(context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
+ do_blend_effect_byte(facf, facf, context->rectx, total_lines, rect1, rect2, data->blend_effect, rect_out);
+ }
+}
+
/*********************** Wipe *************************/
typedef struct WipeZone {
@@ -1570,8 +1883,9 @@ static void copy_wipe_effect(Sequence *dst, Sequence *src)
dst->effectdata = MEM_dupallocN(src->effectdata);
}
-static void do_wipe_effect_byte(Sequence *seq, float facf0, float UNUSED(facf1), int x, int y, unsigned char *rect1,
- unsigned char *rect2, unsigned char *out)
+static void do_wipe_effect_byte(
+ Sequence *seq, float facf0, float UNUSED(facf1), int x, int y,
+ unsigned char *rect1, unsigned char *rect2, unsigned char *out)
{
WipeZone wipezone;
WipeVars *wipe = (WipeVars *)seq->effectdata;
@@ -1636,8 +1950,9 @@ static void do_wipe_effect_byte(Sequence *seq, float facf0, float UNUSED(facf1),
}
}
-static void do_wipe_effect_float(Sequence *seq, float facf0, float UNUSED(facf1), int x, int y, float *rect1,
- float *rect2, float *out)
+static void do_wipe_effect_float(
+ Sequence *seq, float facf0, float UNUSED(facf1), int x, int y,
+ float *rect1, float *rect2, float *out)
{
WipeZone wipezone;
WipeVars *wipe = (WipeVars *)seq->effectdata;
@@ -1695,18 +2010,21 @@ static void do_wipe_effect_float(Sequence *seq, float facf0, float UNUSED(facf1)
}
}
-static ImBuf *do_wipe_effect(const SeqRenderData *context, Sequence *seq, float UNUSED(cfra), float facf0, float facf1,
- ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3)
+static ImBuf *do_wipe_effect(
+ const SeqRenderData *context, Sequence *seq, float UNUSED(cfra), float facf0, float facf1,
+ ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3)
{
ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3);
if (out->rect_float) {
- do_wipe_effect_float(seq, facf0, facf1, context->rectx, context->recty, ibuf1->rect_float,
- ibuf2->rect_float, out->rect_float);
+ do_wipe_effect_float(
+ seq, facf0, facf1, context->rectx, context->recty, ibuf1->rect_float,
+ ibuf2->rect_float, out->rect_float);
}
else {
- do_wipe_effect_byte(seq, facf0, facf1, context->rectx, context->recty, (unsigned char *) ibuf1->rect,
- (unsigned char *) ibuf2->rect, (unsigned char *) out->rect);
+ do_wipe_effect_byte(
+ seq, facf0, facf1, context->rectx, context->recty, (unsigned char *) ibuf1->rect,
+ (unsigned char *) ibuf2->rect, (unsigned char *) out->rect);
}
return out;
@@ -1754,8 +2072,9 @@ static void copy_transform_effect(Sequence *dst, Sequence *src)
dst->effectdata = MEM_dupallocN(src->effectdata);
}
-static void transform_image(int x, int y, ImBuf *ibuf1, ImBuf *out, float scale_x, float scale_y,
- float translate_x, float translate_y, float rotate, int interpolation)
+static void transform_image(
+ int x, int y, ImBuf *ibuf1, ImBuf *out, float scale_x, float scale_y,
+ float translate_x, float translate_y, float rotate, int interpolation)
{
int xo, yo, xi, yi;
float xt, yt, xr, yr;
@@ -1835,8 +2154,9 @@ static void do_transform(Scene *scene, Sequence *seq, float UNUSED(facf0), int x
}
-static ImBuf *do_transform_effect(const SeqRenderData *context, Sequence *seq, float UNUSED(cfra), float facf0,
- float UNUSED(facf1), ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3)
+static ImBuf *do_transform_effect(
+ const SeqRenderData *context, Sequence *seq, float UNUSED(cfra), float facf0,
+ float UNUSED(facf1), ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3)
{
ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3);
@@ -2007,7 +2327,9 @@ static void RVAddBitmaps_float(float *a, float *b, float *c, int width, int heig
}
}
-static void RVIsolateHighlights_float(float *in, float *out, int width, int height, float threshold, float boost, float clamp)
+static void RVIsolateHighlights_float(
+ float *in, float *out, int width, int height,
+ float threshold, float boost, float clamp)
{
int x, y, index;
float intensity;
@@ -2070,8 +2392,9 @@ static void copy_glow_effect(Sequence *dst, Sequence *src)
dst->effectdata = MEM_dupallocN(src->effectdata);
}
-static void do_glow_effect_byte(Sequence *seq, int render_size, float facf0, float UNUSED(facf1), int x, int y,
- unsigned char *rect1, unsigned char *UNUSED(rect2), unsigned char *out)
+static void do_glow_effect_byte(
+ Sequence *seq, int render_size, float facf0, float UNUSED(facf1), int x, int y,
+ unsigned char *rect1, unsigned char *UNUSED(rect2), unsigned char *out)
{
float *outbuf, *inbuf;
GlowVars *glow = (GlowVars *)seq->effectdata;
@@ -2094,8 +2417,9 @@ static void do_glow_effect_byte(Sequence *seq, int render_size, float facf0, flo
MEM_freeN(outbuf);
}
-static void do_glow_effect_float(Sequence *seq, int render_size, float facf0, float UNUSED(facf1), int x, int y,
- float *rect1, float *UNUSED(rect2), float *out)
+static void do_glow_effect_float(
+ Sequence *seq, int render_size, float facf0, float UNUSED(facf1), int x, int y,
+ float *rect1, float *UNUSED(rect2), float *out)
{
float *outbuf = out;
float *inbuf = rect1;
@@ -2107,20 +2431,23 @@ static void do_glow_effect_float(Sequence *seq, int render_size, float facf0, fl
RVAddBitmaps_float(inbuf, outbuf, outbuf, x, y);
}
-static ImBuf *do_glow_effect(const SeqRenderData *context, Sequence *seq, float UNUSED(cfra), float facf0, float facf1,
- ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3)
+static ImBuf *do_glow_effect(
+ const SeqRenderData *context, Sequence *seq, float UNUSED(cfra), float facf0, float facf1,
+ ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3)
{
ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3);
int render_size = 100 * context->rectx / context->scene->r.xsch;
if (out->rect_float) {
- do_glow_effect_float(seq, render_size, facf0, facf1, context->rectx, context->recty,
- ibuf1->rect_float, ibuf2->rect_float, out->rect_float);
+ do_glow_effect_float(
+ seq, render_size, facf0, facf1, context->rectx, context->recty,
+ ibuf1->rect_float, ibuf2->rect_float, out->rect_float);
}
else {
- do_glow_effect_byte(seq, render_size, facf0, facf1, context->rectx, context->recty,
- (unsigned char *) ibuf1->rect, (unsigned char *) ibuf2->rect, (unsigned char *) out->rect);
+ do_glow_effect_byte(
+ seq, render_size, facf0, facf1, context->rectx, context->recty,
+ (unsigned char *) ibuf1->rect, (unsigned char *) ibuf2->rect, (unsigned char *) out->rect);
}
return out;
@@ -2164,8 +2491,9 @@ static int early_out_color(Sequence *UNUSED(seq), float UNUSED(facf0), float UNU
return EARLY_NO_INPUT;
}
-static ImBuf *do_solid_color(const SeqRenderData *context, Sequence *seq, float UNUSED(cfra), float facf0, float facf1,
- ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3)
+static ImBuf *do_solid_color(
+ const SeqRenderData *context, Sequence *seq, float UNUSED(cfra), float facf0, float facf1,
+ ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3)
{
ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3);
@@ -2257,8 +2585,9 @@ static int early_out_multicam(Sequence *UNUSED(seq), float UNUSED(facf0), float
return EARLY_NO_INPUT;
}
-static ImBuf *do_multicam(const SeqRenderData *context, Sequence *seq, float cfra, float UNUSED(facf0), float UNUSED(facf1),
- ImBuf *UNUSED(ibuf1), ImBuf *UNUSED(ibuf2), ImBuf *UNUSED(ibuf3))
+static ImBuf *do_multicam(
+ const SeqRenderData *context, Sequence *seq, float cfra, float UNUSED(facf0), float UNUSED(facf1),
+ ImBuf *UNUSED(ibuf1), ImBuf *UNUSED(ibuf2), ImBuf *UNUSED(ibuf3))
{
ImBuf *i;
ImBuf *out;
@@ -2339,8 +2668,9 @@ static ImBuf *do_adjustment_impl(const SeqRenderData *context, Sequence *seq, fl
return i;
}
-static ImBuf *do_adjustment(const SeqRenderData *context, Sequence *seq, float cfra, float UNUSED(facf0), float UNUSED(facf1),
- ImBuf *UNUSED(ibuf1), ImBuf *UNUSED(ibuf2), ImBuf *UNUSED(ibuf3))
+static ImBuf *do_adjustment(
+ const SeqRenderData *context, Sequence *seq, float cfra, float UNUSED(facf0), float UNUSED(facf1),
+ ImBuf *UNUSED(ibuf1), ImBuf *UNUSED(ibuf2), ImBuf *UNUSED(ibuf3))
{
ImBuf *i = NULL;
ImBuf *out;
@@ -2555,26 +2885,30 @@ void BKE_sequence_effect_speed_rebuild_map(Scene *scene, Sequence *seq, bool for
}
}
-static ImBuf *do_speed_effect(const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra),
- float facf0, float facf1, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3)
+static ImBuf *do_speed_effect(
+ const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra),
+ float facf0, float facf1, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3)
{
ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3);
if (out->rect_float) {
- do_cross_effect_float(facf0, facf1, context->rectx, context->recty,
- ibuf1->rect_float, ibuf2->rect_float, out->rect_float);
+ do_cross_effect_float(
+ facf0, facf1, context->rectx, context->recty,
+ ibuf1->rect_float, ibuf2->rect_float, out->rect_float);
}
else {
- do_cross_effect_byte(facf0, facf1, context->rectx, context->recty,
- (unsigned char *) ibuf1->rect, (unsigned char *) ibuf2->rect, (unsigned char *) out->rect);
+ do_cross_effect_byte(
+ facf0, facf1, context->rectx, context->recty,
+ (unsigned char *) ibuf1->rect, (unsigned char *) ibuf2->rect, (unsigned char *) out->rect);
}
return out;
}
/*********************** overdrop *************************/
-static void do_overdrop_effect(const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra), float facf0, float facf1,
- ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), int start_line, int total_lines, ImBuf *out)
+static void do_overdrop_effect(
+ const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(cfra), float facf0, float facf1,
+ ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), int start_line, int total_lines, ImBuf *out)
{
int x = context->rectx;
int y = total_lines;
@@ -2668,13 +3002,14 @@ static float *make_gaussian_blur_kernel(float rad, int size)
return gausstab;
}
-static void do_gaussian_blur_effect_byte_x(Sequence *seq,
- int start_line,
- int x, int y,
- int frame_width,
- int UNUSED(frame_height),
- unsigned char *rect,
- unsigned char *out)
+static void do_gaussian_blur_effect_byte_x(
+ Sequence *seq,
+ int start_line,
+ int x, int y,
+ int frame_width,
+ int UNUSED(frame_height),
+ unsigned char *rect,
+ unsigned char *out)
{
#define INDEX(_x, _y) (((_y) * (x) + (_x)) * 4)
GaussianBlurVars *data = seq->effectdata;
@@ -2720,13 +3055,14 @@ static void do_gaussian_blur_effect_byte_x(Sequence *seq,
#undef INDEX
}
-static void do_gaussian_blur_effect_byte_y(Sequence *seq,
- int start_line,
- int x, int y,
- int UNUSED(frame_width),
- int frame_height,
- unsigned char *rect,
- unsigned char *out)
+static void do_gaussian_blur_effect_byte_y(
+ Sequence *seq,
+ int start_line,
+ int x, int y,
+ int UNUSED(frame_width),
+ int frame_height,
+ unsigned char *rect,
+ unsigned char *out)
{
#define INDEX(_x, _y) (((_y) * (x) + (_x)) * 4)
GaussianBlurVars *data = seq->effectdata;
@@ -2772,13 +3108,14 @@ static void do_gaussian_blur_effect_byte_y(Sequence *seq,
#undef INDEX
}
-static void do_gaussian_blur_effect_float_x(Sequence *seq,
- int start_line,
- int x, int y,
- int frame_width,
- int UNUSED(frame_height),
- float *rect,
- float *out)
+static void do_gaussian_blur_effect_float_x(
+ Sequence *seq,
+ int start_line,
+ int x, int y,
+ int frame_width,
+ int UNUSED(frame_height),
+ float *rect,
+ float *out)
{
#define INDEX(_x, _y) (((_y) * (x) + (_x)) * 4)
GaussianBlurVars *data = seq->effectdata;
@@ -2815,13 +3152,14 @@ static void do_gaussian_blur_effect_float_x(Sequence *seq,
#undef INDEX
}
-static void do_gaussian_blur_effect_float_y(Sequence *seq,
- int start_line,
- int x, int y,
- int UNUSED(frame_width),
- int frame_height,
- float *rect,
- float *out)
+static void do_gaussian_blur_effect_float_y(
+ Sequence *seq,
+ int start_line,
+ int x, int y,
+ int UNUSED(frame_width),
+ int frame_height,
+ float *rect,
+ float *out)
{
#define INDEX(_x, _y) (((_y) * (x) + (_x)) * 4)
GaussianBlurVars *data = seq->effectdata;
@@ -2860,113 +3198,123 @@ static void do_gaussian_blur_effect_float_y(Sequence *seq,
#undef INDEX
}
-static void do_gaussian_blur_effect_x_cb(const SeqRenderData *context,
- Sequence *seq,
- ImBuf *ibuf,
- int start_line,
- int total_lines,
- ImBuf *out)
+static void do_gaussian_blur_effect_x_cb(
+ const SeqRenderData *context,
+ Sequence *seq,
+ ImBuf *ibuf,
+ int start_line,
+ int total_lines,
+ ImBuf *out)
{
if (out->rect_float) {
float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
- slice_get_float_buffers(context,
- ibuf,
- NULL,
- NULL,
- out,
- start_line,
- &rect1,
- &rect2,
- NULL,
- &rect_out);
-
- do_gaussian_blur_effect_float_x(seq,
- start_line,
- context->rectx,
- total_lines,
- context->rectx,
- context->recty,
- ibuf->rect_float,
- rect_out);
+ slice_get_float_buffers(
+ context,
+ ibuf,
+ NULL,
+ NULL,
+ out,
+ start_line,
+ &rect1,
+ &rect2,
+ NULL,
+ &rect_out);
+
+ do_gaussian_blur_effect_float_x(
+ seq,
+ start_line,
+ context->rectx,
+ total_lines,
+ context->rectx,
+ context->recty,
+ ibuf->rect_float,
+ rect_out);
}
else {
unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
- slice_get_byte_buffers(context,
- ibuf,
- NULL,
- NULL,
- out,
- start_line,
- &rect1,
- &rect2,
- NULL,
- &rect_out);
-
- do_gaussian_blur_effect_byte_x(seq,
- start_line,
- context->rectx,
- total_lines,
- context->rectx,
- context->recty,
- (unsigned char *) ibuf->rect,
- rect_out);
- }
-}
-
-static void do_gaussian_blur_effect_y_cb(const SeqRenderData *context,
- Sequence *seq,
- ImBuf *ibuf,
- int start_line,
- int total_lines,
- ImBuf *out)
+ slice_get_byte_buffers(
+ context,
+ ibuf,
+ NULL,
+ NULL,
+ out,
+ start_line,
+ &rect1,
+ &rect2,
+ NULL,
+ &rect_out);
+
+ do_gaussian_blur_effect_byte_x(
+ seq,
+ start_line,
+ context->rectx,
+ total_lines,
+ context->rectx,
+ context->recty,
+ (unsigned char *) ibuf->rect,
+ rect_out);
+ }
+}
+
+static void do_gaussian_blur_effect_y_cb(
+ const SeqRenderData *context,
+ Sequence *seq,
+ ImBuf *ibuf,
+ int start_line,
+ int total_lines,
+ ImBuf *out)
{
if (out->rect_float) {
float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
- slice_get_float_buffers(context,
- ibuf,
- NULL,
- NULL,
- out,
- start_line,
- &rect1,
- &rect2,
- NULL,
- &rect_out);
-
- do_gaussian_blur_effect_float_y(seq,
- start_line,
- context->rectx,
- total_lines,
- context->rectx,
- context->recty,
- ibuf->rect_float,
- rect_out);
+ slice_get_float_buffers(
+ context,
+ ibuf,
+ NULL,
+ NULL,
+ out,
+ start_line,
+ &rect1,
+ &rect2,
+ NULL,
+ &rect_out);
+
+ do_gaussian_blur_effect_float_y(
+ seq,
+ start_line,
+ context->rectx,
+ total_lines,
+ context->rectx,
+ context->recty,
+ ibuf->rect_float,
+ rect_out);
}
else {
unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
- slice_get_byte_buffers(context,
- ibuf,
- NULL,
- NULL,
- out,
- start_line,
- &rect1,
- &rect2,
- NULL,
- &rect_out);
-
- do_gaussian_blur_effect_byte_y(seq,
- start_line,
- context->rectx,
- total_lines,
- context->rectx,
- context->recty,
- (unsigned char *) ibuf->rect,
- rect_out);
+ slice_get_byte_buffers(
+ context,
+ ibuf,
+ NULL,
+ NULL,
+ out,
+ start_line,
+ &rect1,
+ &rect2,
+ NULL,
+ &rect_out);
+
+ do_gaussian_blur_effect_byte_y(
+ seq,
+ start_line,
+ context->rectx,
+ total_lines,
+ context->rectx,
+ context->recty,
+ (unsigned char *) ibuf->rect,
+ rect_out);
}
}
@@ -2985,10 +3333,11 @@ typedef struct RenderGaussianBlurEffectThread {
int start_line, tot_line;
} RenderGaussianBlurEffectThread;
-static void render_effect_execute_init_handle(void *handle_v,
- int start_line,
- int tot_line,
- void *init_data_v)
+static void render_effect_execute_init_handle(
+ void *handle_v,
+ int start_line,
+ int tot_line,
+ void *init_data_v)
{
RenderGaussianBlurEffectThread *handle = (RenderGaussianBlurEffectThread *) handle_v;
RenderGaussianBlurEffectInitData *init_data = (RenderGaussianBlurEffectInitData *) init_data_v;
@@ -3005,36 +3354,39 @@ static void render_effect_execute_init_handle(void *handle_v,
static void *render_effect_execute_do_x_thread(void *thread_data_v)
{
RenderGaussianBlurEffectThread *thread_data = (RenderGaussianBlurEffectThread *) thread_data_v;
- do_gaussian_blur_effect_x_cb(thread_data->context,
- thread_data->seq,
- thread_data->ibuf,
- thread_data->start_line,
- thread_data->tot_line,
- thread_data->out);
+ do_gaussian_blur_effect_x_cb(
+ thread_data->context,
+ thread_data->seq,
+ thread_data->ibuf,
+ thread_data->start_line,
+ thread_data->tot_line,
+ thread_data->out);
return NULL;
}
static void *render_effect_execute_do_y_thread(void *thread_data_v)
{
RenderGaussianBlurEffectThread *thread_data = (RenderGaussianBlurEffectThread *) thread_data_v;
- do_gaussian_blur_effect_y_cb(thread_data->context,
- thread_data->seq,
- thread_data->ibuf,
- thread_data->start_line,
- thread_data->tot_line,
- thread_data->out);
+ do_gaussian_blur_effect_y_cb(
+ thread_data->context,
+ thread_data->seq,
+ thread_data->ibuf,
+ thread_data->start_line,
+ thread_data->tot_line,
+ thread_data->out);
return NULL;
}
-static ImBuf *do_gaussian_blur_effect(const SeqRenderData *context,
- Sequence *seq,
- float UNUSED(cfra),
- float UNUSED(facf0),
- float UNUSED(facf1),
- ImBuf *ibuf1,
- ImBuf *UNUSED(ibuf2),
- ImBuf *UNUSED(ibuf3))
+static ImBuf *do_gaussian_blur_effect(
+ const SeqRenderData *context,
+ Sequence *seq,
+ float UNUSED(cfra),
+ float UNUSED(facf0),
+ float UNUSED(facf1),
+ ImBuf *ibuf1,
+ ImBuf *UNUSED(ibuf2),
+ ImBuf *UNUSED(ibuf3))
{
ImBuf *out = prepare_effect_imbufs(context, ibuf1, NULL, NULL);
@@ -3045,22 +3397,24 @@ static ImBuf *do_gaussian_blur_effect(const SeqRenderData *context,
init_data.ibuf = ibuf1;
init_data.out = out;
- IMB_processor_apply_threaded(out->y,
- sizeof(RenderGaussianBlurEffectThread),
- &init_data,
- render_effect_execute_init_handle,
- render_effect_execute_do_x_thread);
+ IMB_processor_apply_threaded(
+ out->y,
+ sizeof(RenderGaussianBlurEffectThread),
+ &init_data,
+ render_effect_execute_init_handle,
+ render_effect_execute_do_x_thread);
ibuf1 = out;
init_data.ibuf = ibuf1;
out = prepare_effect_imbufs(context, ibuf1, NULL, NULL);
init_data.out = out;
- IMB_processor_apply_threaded(out->y,
- sizeof(RenderGaussianBlurEffectThread),
- &init_data,
- render_effect_execute_init_handle,
- render_effect_execute_do_y_thread);
+ IMB_processor_apply_threaded(
+ out->y,
+ sizeof(RenderGaussianBlurEffectThread),
+ &init_data,
+ render_effect_execute_init_handle,
+ render_effect_execute_do_y_thread);
IMB_freeImBuf(ibuf1);
@@ -3104,8 +3458,9 @@ static int early_out_text(Sequence *seq, float UNUSED(facf0), float UNUSED(facf1
return EARLY_NO_INPUT;
}
-static ImBuf *do_text_effect(const SeqRenderData *context, Sequence *seq, float UNUSED(cfra), float UNUSED(facf0), float UNUSED(facf1),
- ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3)
+static ImBuf *do_text_effect(
+ const SeqRenderData *context, Sequence *seq, float UNUSED(cfra), float UNUSED(facf0), float UNUSED(facf1),
+ ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3)
{
ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3);
TextVars *data = seq->effectdata;
@@ -3336,6 +3691,36 @@ static struct SeqEffectHandle get_sequence_effect_impl(int seq_type)
rval.execute_slice = do_mul_effect;
rval.early_out = early_out_mul_input2;
break;
+ case SEQ_TYPE_SCREEN:
+ case SEQ_TYPE_OVERLAY:
+ case SEQ_TYPE_BURN:
+ case SEQ_TYPE_LINEAR_BURN:
+ case SEQ_TYPE_DARKEN:
+ case SEQ_TYPE_LIGHTEN:
+ case SEQ_TYPE_DODGE:
+ case SEQ_TYPE_SOFT_LIGHT:
+ case SEQ_TYPE_HARD_LIGHT:
+ case SEQ_TYPE_PIN_LIGHT:
+ case SEQ_TYPE_LIN_LIGHT:
+ case SEQ_TYPE_VIVID_LIGHT:
+ case SEQ_TYPE_BLEND_COLOR:
+ case SEQ_TYPE_HUE:
+ case SEQ_TYPE_SATURATION:
+ case SEQ_TYPE_VALUE:
+ case SEQ_TYPE_DIFFERENCE:
+ case SEQ_TYPE_EXCLUSION:
+ rval.multithreaded = true;
+ rval.execute_slice = do_blend_mode_effect;
+ rval.early_out = early_out_mul_input2;
+ break;
+ case SEQ_TYPE_COLORMIX:
+ rval.multithreaded = true;
+ rval.init = init_colormix_effect;
+ rval.free = free_effect_default;
+ rval.copy = copy_effect_default;
+ rval.execute_slice = do_colormix_effect;
+ rval.early_out = early_out_mul_input2;
+ break;
case SEQ_TYPE_ALPHAOVER:
rval.multithreaded = true;
rval.init = init_alpha_over_or_under;
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index ced94af26d2..2319d36ab16 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -1164,6 +1164,7 @@ static const char *give_seqname_by_type(int type)
case SEQ_TYPE_ALPHAOVER: return "Alpha Over";
case SEQ_TYPE_ALPHAUNDER: return "Alpha Under";
case SEQ_TYPE_OVERDROP: return "Over Drop";
+ case SEQ_TYPE_COLORMIX: return "Color Mix";
case SEQ_TYPE_WIPE: return "Wipe";
case SEQ_TYPE_GLOW: return "Glow";
case SEQ_TYPE_TRANSFORM: return "Transform";
@@ -3321,7 +3322,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq
context->scene->r.seq_prev_type = 3 /* == OB_SOLID */;
/* opengl offscreen render */
- context->eval_ctx->engine = RE_engines_find(scene->view_render.engine_id);
+ context->eval_ctx->engine_type = RE_engines_find(scene->view_render.engine_id);
BKE_scene_graph_update_for_newframe(context->eval_ctx, depsgraph, context->bmain, scene, view_layer);
ibuf = sequencer_view3d_cb(
/* set for OpenGL render (NULL when scrubbing) */
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index d7d274f32b5..e3af77166a9 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -74,6 +74,7 @@ variables on the UI for now
#include "BKE_curve.h"
#include "BKE_effect.h"
#include "BKE_global.h"
+#include "BKE_group.h"
#include "BKE_modifier.h"
#include "BKE_softbody.h"
#include "BKE_pointcache.h"
@@ -520,29 +521,20 @@ static void ccd_build_deflector_hash(ViewLayer *view_layer, Group *group, Object
if (!hash) return;
+ /* Explicit collision group. */
if (group) {
- /* Explicit collision group */
- for (GroupObject *go = group->gobject.first; go; go = go->next) {
- ob = go->ob;
-
- if (ob == vertexowner || ob->type != OB_MESH)
- continue;
-
- ccd_build_deflector_hash_single(hash, ob);
- }
+ view_layer = group->view_layer;
}
- else {
- for (Base *base = FIRSTBASE(view_layer); base; base = base->next) {
- /*Only proceed for mesh object in same layer */
- if (base->object->type == OB_MESH) {
- ob = base->object;
- if ((vertexowner) && (ob == vertexowner)) {
- /* if vertexowner is given we don't want to check collision with owner object */
- continue;
- }
- ccd_build_deflector_hash_single(hash, ob);
+ for (Base *base = FIRSTBASE(view_layer); base; base = base->next) {
+ /* Only proceed for mesh object in same layer. */
+ if (base->object->type == OB_MESH) {
+ ob = base->object;
+ if (ob == vertexowner) {
+ /* If vertexowner is given we don't want to check collision with owner object. */
+ continue;
}
+ ccd_build_deflector_hash_single(hash, ob);
}
}
}
@@ -566,31 +558,23 @@ static void ccd_update_deflector_hash(ViewLayer *view_layer, Group *group, Objec
if ((!hash) || (!vertexowner)) return;
+ /* Explicit collision group. */
if (group) {
- /* Explicit collision group */
- for (GroupObject *go = group->gobject.first; go; go = go->next) {
- ob = go->ob;
+ view_layer = group->view_layer;
+ }
- if (ob == vertexowner || ob->type != OB_MESH)
+ for (Base *base = FIRSTBASE(view_layer); base; base = base->next) {
+ /* Only proceed for mesh object in same layer. */
+ if (base->object->type == OB_MESH) {
+ ob = base->object;
+ if (ob == vertexowner) {
+ /* If vertexowner is given we don't want to check collision with owner object. */
continue;
+ }
ccd_update_deflector_hash_single(hash, ob);
}
}
- else {
- for (Base *base = FIRSTBASE(view_layer); base; base = base->next) {
- /*Only proceed for mesh object in same layer */
- if (base->object->type == OB_MESH) {
- ob = base->object;
- if (ob == vertexowner) {
- /* if vertexowner is given we don't want to check collision with owner object */
- continue;
- }
-
- ccd_update_deflector_hash_single(hash, ob);
- }
- }
- }
}
@@ -979,29 +963,21 @@ static void free_softbody_intern(SoftBody *sb)
/**
* \note group overrides scene when not NULL.
*/
-static bool are_there_deflectors(ViewLayer *view_layer, Group *group)
+static bool are_there_deflectors(ViewLayer *view_layer)
{
- if (group) {
- for (GroupObject *go = group->gobject.first; go; go = go->next) {
- if (go->ob->pd && go->ob->pd->deflect)
+ for (Base *base = FIRSTBASE(view_layer); base; base = base->next) {
+ if (base->object->pd) {
+ if (base->object->pd->deflect)
return 1;
}
}
- else {
- for (Base *base = FIRSTBASE(view_layer); base; base = base->next) {
- if (base->object->pd) {
- if (base->object->pd->deflect)
- return 1;
- }
- }
- }
return 0;
}
static int query_external_colliders(ViewLayer *view_layer, Group *group)
{
- return(are_there_deflectors(view_layer, group));
+ return(are_there_deflectors(group != NULL ? group->view_layer : view_layer));
}
/* --- dependency information functions*/
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index 50bb3a5f10d..122b605f160 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -1165,6 +1165,10 @@ void set_current_material_texture(Material *ma, Tex *newtex)
ma->mtex[act] = BKE_texture_mtex_add();
/* Reset this slot's ON/OFF toggle, for materials, when slot was empty. */
ma->septex &= ~(1 << act);
+ /* For volumes the default UV texture coordinates are not available. */
+ if (ma->material_type == MA_TYPE_VOLUME) {
+ ma->mtex[act]->texco = TEXCO_ORCO;
+ }
}
ma->mtex[act]->tex = newtex;
diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c
index b8dfb217c16..edddeb41cc8 100644
--- a/source/blender/blenkernel/intern/tracking_stabilize.c
+++ b/source/blender/blenkernel/intern/tracking_stabilize.c
@@ -41,13 +41,14 @@
#include "BLI_utildefines.h"
#include "BLI_sort_utils.h"
+#include "BLI_ghash.h"
#include "BLI_math_vector.h"
#include "BLI_math.h"
+#include "BLI_task.h"
#include "BKE_tracking.h"
#include "BKE_movieclip.h"
#include "BKE_fcurve.h"
-#include "BLI_ghash.h"
#include "MEM_guardedalloc.h"
#include "IMB_imbuf_types.h"
@@ -1491,6 +1492,35 @@ void BKE_tracking_stabilization_data_get(MovieClip *clip,
discard_stabilization_working_context(ctx);
}
+
+typedef void (*interpolation_func)(struct ImBuf *, struct ImBuf *, float, float, int, int);
+
+typedef struct TrackingStabilizeFrameInterpolationData {
+ ImBuf *ibuf;
+ ImBuf *tmpibuf;
+ float (*mat)[4];
+
+ interpolation_func interpolation;
+} TrackingStabilizeFrameInterpolationData;
+
+static void tracking_stabilize_frame_interpolation_cb(void *userdata, int j)
+{
+ TrackingStabilizeFrameInterpolationData *data = userdata;
+ ImBuf *ibuf = data->ibuf;
+ ImBuf *tmpibuf = data->tmpibuf;
+ float (*mat)[4] = data->mat;
+
+ interpolation_func interpolation = data->interpolation;
+
+ for (int i = 0; i < tmpibuf->x; i++) {
+ float vec[3] = {i, j, 0.0f};
+
+ mul_v3_m4v3(vec, mat, vec);
+
+ interpolation(ibuf, tmpibuf, vec[0], vec[1], i, j);
+ }
+}
+
/* Stabilize given image buffer using stabilization data for a specified
* frame number.
*
@@ -1511,8 +1541,8 @@ ImBuf *BKE_tracking_stabilize_frame(MovieClip *clip,
int width = ibuf->x, height = ibuf->y;
float pixel_aspect = tracking->camera.pixel_aspect;
float mat[4][4];
- int j, filter = tracking->stabilization.filter;
- void (*interpolation)(struct ImBuf *, struct ImBuf *, float, float, int, int) = NULL;
+ int filter = tracking->stabilization.filter;
+ interpolation_func interpolation = NULL;
int ibuf_flags;
if (translation)
@@ -1563,24 +1593,14 @@ ImBuf *BKE_tracking_stabilize_frame(MovieClip *clip,
/* fallback to default interpolation method */
interpolation = nearest_interpolation;
- /* This function is only used for display in clip editor and
- * sequencer only, which would only benefit of using threads
- * here.
- *
- * But need to keep an eye on this if the function will be
- * used in other cases.
- */
-#pragma omp parallel for if (tmpibuf->y > 128)
- for (j = 0; j < tmpibuf->y; j++) {
- int i;
- for (i = 0; i < tmpibuf->x; i++) {
- float vec[3] = {i, j, 0.0f};
-
- mul_v3_m4v3(vec, mat, vec);
-
- interpolation(ibuf, tmpibuf, vec[0], vec[1], i, j);
- }
- }
+ TrackingStabilizeFrameInterpolationData data = {
+ .ibuf = ibuf, .tmpibuf = tmpibuf, .mat = mat,
+ .interpolation = interpolation
+ };
+ BLI_task_parallel_range(0, tmpibuf->y,
+ &data,
+ tracking_stabilize_frame_interpolation_cb,
+ tmpibuf->y > 128);
if (tmpibuf->rect_float)
tmpibuf->userflags |= IB_RECT_INVALID;
diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c
index 785fd71df69..8554cf0fb28 100644
--- a/source/blender/blenkernel/intern/workspace.c
+++ b/source/blender/blenkernel/intern/workspace.c
@@ -113,6 +113,18 @@ static void *workspace_relation_get_data_matching_parent(
}
}
+static void workspace_relation_remove_from_value(
+ ListBase *relation_list, const void *value)
+{
+ for (WorkSpaceDataRelation *relation = relation_list->first, *relation_next; relation; relation = relation_next) {
+ relation_next = relation->next;
+
+ if (relation->value == value) {
+ workspace_relation_remove(relation_list, relation);
+ }
+ }
+}
+
/**
* Checks if \a screen is already used within any workspace. A screen should never be assigned to multiple
* WorkSpaceLayouts, but that should be ensured outside of the BKE_workspace module and without such checks.
@@ -151,15 +163,12 @@ WorkSpace *BKE_workspace_add(Main *bmain, const char *name)
*/
void BKE_workspace_free(WorkSpace *workspace)
{
- for (WorkSpaceDataRelation *relation = workspace->hook_layout_relations.first, *relation_next;
- relation;
- relation = relation_next)
- {
- relation_next = relation->next;
- workspace_relation_remove(&workspace->hook_layout_relations, relation);
- }
+ BKE_workspace_relations_free(&workspace->hook_layout_relations);
+ BKE_workspace_relations_free(&workspace->scene_viewlayer_relations);
+
BLI_freelistN(&workspace->layouts);
BLI_freelistN(&workspace->transform_orientations);
+
BKE_viewrender_free(&workspace->view_render);
}
@@ -237,9 +246,28 @@ void BKE_workspace_layout_remove(
BLI_freelinkN(&workspace->layouts, layout);
}
+void BKE_workspace_relations_free(
+ ListBase *relation_list)
+{
+ for (WorkSpaceDataRelation *relation = relation_list->first, *relation_next; relation; relation = relation_next) {
+ relation_next = relation->next;
+ workspace_relation_remove(relation_list, relation);
+ }
+}
+
+
/* -------------------------------------------------------------------- */
/* General Utils */
+void BKE_workspace_view_layer_remove_references(
+ const Main *bmain,
+ const ViewLayer *view_layer)
+{
+ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ workspace_relation_remove_from_value(&workspace->scene_viewlayer_relations, view_layer);
+ }
+}
+
void BKE_workspace_transform_orientation_remove(
WorkSpace *workspace, TransformOrientation *orientation)
{
@@ -386,23 +414,24 @@ void BKE_workspace_active_screen_set(WorkSpaceInstanceHook *hook, WorkSpace *wor
}
#ifdef USE_WORKSPACE_MODE
-eObjectMode BKE_workspace_object_mode_get(const WorkSpace *workspace)
+eObjectMode BKE_workspace_object_mode_get(const WorkSpace *workspace, const Scene *scene)
{
- Base *active_base = BKE_workspace_active_base_get(workspace);
+ Base *active_base = BKE_workspace_active_base_get(workspace, scene);
return active_base ? active_base->object->mode : OB_MODE_OBJECT;
}
-void BKE_workspace_object_mode_set(WorkSpace *workspace, const eObjectMode mode)
+void BKE_workspace_object_mode_set(WorkSpace *workspace, Scene *scene, const eObjectMode mode)
{
- Base *active_base = BKE_workspace_active_base_get(workspace);
+ Base *active_base = BKE_workspace_active_base_get(workspace, scene);
if (active_base) {
active_base->object->mode = mode;
}
}
#endif
-Base *BKE_workspace_active_base_get(const WorkSpace *workspace)
+Base *BKE_workspace_active_base_get(const WorkSpace *workspace, const Scene *scene)
{
- return workspace->view_layer->basact;
+ ViewLayer *view_layer = BKE_workspace_view_layer_get(workspace, scene);
+ return view_layer->basact;
}
ListBase *BKE_workspace_transform_orientations_get(WorkSpace *workspace)
@@ -410,13 +439,13 @@ ListBase *BKE_workspace_transform_orientations_get(WorkSpace *workspace)
return &workspace->transform_orientations;
}
-ViewLayer *BKE_workspace_view_layer_get(const WorkSpace *workspace)
+ViewLayer *BKE_workspace_view_layer_get(const WorkSpace *workspace, const Scene *scene)
{
- return workspace->view_layer;
+ return workspace_relation_get_data_matching_parent(&workspace->scene_viewlayer_relations, scene);
}
-void BKE_workspace_view_layer_set(WorkSpace *workspace, ViewLayer *layer)
+void BKE_workspace_view_layer_set(WorkSpace *workspace, ViewLayer *layer, Scene *scene)
{
- workspace->view_layer = layer;
+ workspace_relation_ensure_updated(&workspace->scene_viewlayer_relations, scene, layer);
}
ListBase *BKE_workspace_layouts_get(WorkSpace *workspace)
@@ -486,7 +515,7 @@ void BKE_workspace_update_tagged(struct EvaluationContext *eval_ctx,
WorkSpace *workspace,
Scene *scene)
{
- ViewLayer *view_layer = BKE_workspace_view_layer_get(workspace);
+ ViewLayer *view_layer = BKE_workspace_view_layer_get(workspace, scene);
struct Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene,
view_layer,
true);
diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h
index 2720c0058b7..b4819ff4e55 100644
--- a/source/blender/blenlib/BLI_ghash.h
+++ b/source/blender/blenlib/BLI_ghash.h
@@ -20,16 +20,18 @@
*
* The Original Code is: all of this file.
*
- * Contributor(s): none yet.
- *
* ***** END GPL LICENSE BLOCK *****
*/
-
+
#ifndef __BLI_GHASH_H__
#define __BLI_GHASH_H__
/** \file BLI_ghash.h
* \ingroup bli
+ *
+ * GHash is a hash-map implementation (unordered key, value pairs).
+ *
+ * This is also used to implement a 'set' (see #GSet below).
*/
#include "BLI_sys_types.h" /* for bool */
@@ -81,11 +83,14 @@ enum {
/* *** */
-GHash *BLI_ghash_new_ex(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info,
- const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
-GHash *BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
-GHash *BLI_ghash_copy(GHash *gh, GHashKeyCopyFP keycopyfp,
- GHashValCopyFP valcopyfp) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+GHash *BLI_ghash_new_ex(
+ GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info,
+ const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+GHash *BLI_ghash_new(
+ GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+GHash *BLI_ghash_copy(
+ GHash *gh, GHashKeyCopyFP keycopyfp,
+ GHashValCopyFP valcopyfp) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp);
void BLI_ghash_reserve(GHash *gh, const unsigned int nentries_reserve);
void BLI_ghash_insert(GHash *gh, void *key, void *val);
@@ -97,9 +102,11 @@ void **BLI_ghash_lookup_p(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT;
bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val) ATTR_WARN_UNUSED_RESULT;
bool BLI_ghash_ensure_p_ex(GHash *gh, const void *key, void ***r_key, void ***r_val) ATTR_WARN_UNUSED_RESULT;
bool BLI_ghash_remove(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp);
-void BLI_ghash_clear(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp);
-void BLI_ghash_clear_ex(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp,
- const unsigned int nentries_reserve);
+void BLI_ghash_clear(
+ GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp);
+void BLI_ghash_clear_ex(
+ GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp,
+ const unsigned int nentries_reserve);
void *BLI_ghash_popkey(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp) ATTR_WARN_UNUSED_RESULT;
bool BLI_ghash_haskey(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT;
bool BLI_ghash_pop(GHash *gh, GHashIterState *state, void **r_key, void **r_val) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
@@ -193,18 +200,26 @@ bool BLI_ghashutil_uinthash_v4_cmp(const void *a, const void *b);
/** \} */
-GHash *BLI_ghash_ptr_new_ex(const char *info,
- const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
-GHash *BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
-GHash *BLI_ghash_str_new_ex(const char *info,
- const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
-GHash *BLI_ghash_str_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
-GHash *BLI_ghash_int_new_ex(const char *info,
- const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
-GHash *BLI_ghash_int_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
-GHash *BLI_ghash_pair_new_ex(const char *info,
- const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
-GHash *BLI_ghash_pair_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+GHash *BLI_ghash_ptr_new_ex(
+ const char *info,
+ const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+GHash *BLI_ghash_ptr_new(
+ const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+GHash *BLI_ghash_str_new_ex(
+ const char *info,
+ const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+GHash *BLI_ghash_str_new(
+ const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+GHash *BLI_ghash_int_new_ex(
+ const char *info,
+ const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+GHash *BLI_ghash_int_new(
+ const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+GHash *BLI_ghash_pair_new_ex(
+ const char *info,
+ const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+GHash *BLI_ghash_pair_new(
+ const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
typedef struct GHashPair {
const void *first;
@@ -216,8 +231,12 @@ unsigned int BLI_ghashutil_pairhash(const void *ptr);
bool BLI_ghashutil_paircmp(const void *a, const void *b);
void BLI_ghashutil_pairfree(void *ptr);
-
-/* *** */
+/**
+ * GSet is a 'set' implementation (unordered collection of unique elements).
+ *
+ * Internally this is a 'GHash' without any keys,
+ * which is why this API's are in the same header & source file.
+ */
typedef struct GSet GSet;
@@ -237,8 +256,9 @@ typedef struct GSetIterator {
;
} GSetIterator;
-GSet *BLI_gset_new_ex(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info,
- const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+GSet *BLI_gset_new_ex(
+ GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info,
+ const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
GSet *BLI_gset_new(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
GSet *BLI_gset_copy(GSet *gs, GSetKeyCopyFP keycopyfp) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
unsigned int BLI_gset_size(GSet *gs) ATTR_WARN_UNUSED_RESULT;
diff --git a/source/blender/blenlib/BLI_sys_types.h b/source/blender/blenlib/BLI_sys_types.h
index 9477f61713c..80ee50621ca 100644
--- a/source/blender/blenlib/BLI_sys_types.h
+++ b/source/blender/blenlib/BLI_sys_types.h
@@ -47,7 +47,9 @@
extern "C" {
#endif
-#if defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD_kernel__) || defined(__GNU__)
+#if defined(__linux__) || defined(__GNU__) || \
+ defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD_kernel__) || \
+ defined(__HAIKU__)
/* Linux-i386, Linux-Alpha, Linux-ppc */
#include <stdint.h>
diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c
index 36a0d1c1641..ad53457f863 100644
--- a/source/blender/blenlib/intern/fileops.c
+++ b/source/blender/blenlib/intern/fileops.c
@@ -621,7 +621,21 @@ static int recursive_operation(const char *startfrom, const char *startto,
if (to)
join_dirfile_alloc(&to_path, &to_alloc_len, to, dirent->d_name);
- if (dirent->d_type == DT_DIR) {
+ bool is_dir;
+
+#ifdef __HAIKU__
+ {
+ struct stat st_dir;
+ char filename[FILE_MAX];
+ BLI_path_join(filename, sizeof(filename), startfrom, dirent->d_name, NULL);
+ lstat(filename, &st_dir);
+ is_dir = S_ISDIR(st_dir.st_mode);
+ }
+#else
+ is_dir = (dirent->d_type == DT_DIR);
+#endif
+
+ if (is_dir) {
/* recursively dig into a subfolder */
ret = recursive_operation(from_path, to_path, callback_dir_pre, callback_file, callback_dir_post);
}
diff --git a/source/blender/blenlib/intern/math_color_blend_inline.c b/source/blender/blenlib/intern/math_color_blend_inline.c
index dc3874f83a2..1af2a0cd6a2 100644
--- a/source/blender/blenlib/intern/math_color_blend_inline.c
+++ b/source/blender/blenlib/intern/math_color_blend_inline.c
@@ -439,10 +439,10 @@ MINLINE void blend_color_vividlight_byte(unsigned char dst[4], unsigned const ch
int temp;
if (src2[i] == 255) {
- temp = 255;
+ temp = (src1[i] == 0) ? 127 : 255;
}
else if (src2[i] == 0) {
- temp = 0;
+ temp = (src1[i] == 255) ? 127 : 0;
}
else if (src2[i] > 127) {
temp = min_ii(((src1[i]) * 255) / (2 * (255 - src2[i])), 255);
@@ -784,7 +784,7 @@ MINLINE void blend_color_add_alpha_float(float dst[4], const float src1[4], cons
MINLINE void blend_color_overlay_float(float dst[4], const float src1[4], const float src2[4])
{
const float fac = src2[3];
- if (fac != 0.0f && fac < 1.0f) {
+ if (fac != 0.0f) {
const float mfac = 1.0f - fac;
int i = 3;
@@ -810,7 +810,7 @@ MINLINE void blend_color_overlay_float(float dst[4], const float src1[4], const
MINLINE void blend_color_hardlight_float(float dst[4], const float src1[4], const float src2[4])
{
const float fac = src2[3];
- if (fac != 0.0f && fac < 1.0f) {
+ if (fac != 0.0f) {
const float mfac = 1.0f - fac;
int i = 3;
@@ -835,7 +835,7 @@ MINLINE void blend_color_hardlight_float(float dst[4], const float src1[4], cons
MINLINE void blend_color_burn_float(float dst[4], const float src1[4], const float src2[4])
{
const float fac = src2[3];
- if (fac != 0.0f && fac < 1.0f) {
+ if (fac != 0.0f) {
const float mfac = 1.0f - fac;
int i = 3;
@@ -853,7 +853,7 @@ MINLINE void blend_color_burn_float(float dst[4], const float src1[4], const flo
MINLINE void blend_color_linearburn_float(float dst[4], const float src1[4], const float src2[4])
{
const float fac = src2[3];
- if (fac != 0.0f && fac < 1.0f) {
+ if (fac != 0.0f) {
const float mfac = 1.0f - fac;
int i = 3;
@@ -872,7 +872,7 @@ MINLINE void blend_color_linearburn_float(float dst[4], const float src1[4], con
MINLINE void blend_color_dodge_float(float dst[4], const float src1[4], const float src2[4])
{
const float fac = src2[3];
- if (fac != 0.0f && fac < 1.0f) {
+ if (fac != 0.0f) {
const float mfac = 1.0f - fac;
int i = 3;
@@ -890,7 +890,7 @@ MINLINE void blend_color_dodge_float(float dst[4], const float src1[4], const fl
MINLINE void blend_color_screen_float(float dst[4], const float src1[4], const float src2[4])
{
const float fac = src2[3];
- if (fac != 0.0f && fac < 1.0f) {
+ if (fac != 0.0f) {
const float mfac = 1.0f - fac;
int i = 3;
@@ -908,7 +908,7 @@ MINLINE void blend_color_screen_float(float dst[4], const float src1[4], const f
MINLINE void blend_color_softlight_float(float dst[4], const float src1[4], const float src2[4])
{
const float fac = src2[3];
- if (fac != 0.0f && fac < 1.0f) {
+ if (fac != 0.0f) {
const float mfac = 1.0f - fac;
int i = 3;
@@ -933,7 +933,7 @@ MINLINE void blend_color_softlight_float(float dst[4], const float src1[4], cons
MINLINE void blend_color_pinlight_float(float dst[4], const float src1[4], const float src2[4])
{
const float fac = src2[3];
- if (fac != 0.0f && fac < 1.0f) {
+ if (fac != 0.0f) {
const float mfac = 1.0f - fac;
int i = 3;
@@ -959,7 +959,7 @@ MINLINE void blend_color_pinlight_float(float dst[4], const float src1[4], const
MINLINE void blend_color_linearlight_float(float dst[4], const float src1[4], const float src2[4])
{
const float fac = src2[3];
- if (fac != 0.0f && fac < 1.0f) {
+ if (fac != 0.0f) {
const float mfac = 1.0f - fac;
int i = 3;
@@ -985,7 +985,7 @@ MINLINE void blend_color_linearlight_float(float dst[4], const float src1[4], co
MINLINE void blend_color_vividlight_float(float dst[4], const float src1[4], const float src2[4])
{
const float fac = src2[3];
- if (fac != 0.0f && fac < 1.0f) {
+ if (fac != 0.0f) {
const float mfac = 1.0f - fac;
int i = 3;
@@ -993,10 +993,10 @@ MINLINE void blend_color_vividlight_float(float dst[4], const float src1[4], con
float temp;
if (src2[i] == 1.0f) {
- temp = 1.0f;
+ temp = (src1[i] == 0.0f) ? 0.5f : 1.0f;
}
else if (src2[i] == 0.0f) {
- temp = 0.0f;
+ temp = (src1[i] == 1.0f) ? 0.5f : 0.0f;
}
else if (src2[i] > 0.5f) {
temp = min_ff(((src1[i]) * 1.0f) / (2.0f * (1.0f - src2[i])), 1.0f);
@@ -1016,7 +1016,7 @@ MINLINE void blend_color_vividlight_float(float dst[4], const float src1[4], con
MINLINE void blend_color_difference_float(float dst[4], const float src1[4], const float src2[4])
{
const float fac = src2[3];
- if (fac != 0.0f && fac < 1.0f) {
+ if (fac != 0.0f) {
const float mfac = 1.0f - fac;
int i = 3;
@@ -1034,7 +1034,7 @@ MINLINE void blend_color_difference_float(float dst[4], const float src1[4], con
MINLINE void blend_color_exclusion_float(float dst[4], const float src1[4], const float src2[4])
{
const float fac = src2[3];
- if (fac != 0.0f && fac < 1.0f) {
+ if (fac != 0.0f) {
const float mfac = 1.0f - fac;
int i = 3;
@@ -1053,7 +1053,7 @@ MINLINE void blend_color_exclusion_float(float dst[4], const float src1[4], cons
MINLINE void blend_color_color_float(float dst[4], const float src1[4], const float src2[4])
{
const float fac = src2[3];
- if (fac != 0.0f && fac < 1.0f) {
+ if (fac != 0.0f) {
const float mfac = 1.0f - fac;
float h1, s1, v1;
float h2, s2, v2;
@@ -1081,7 +1081,7 @@ MINLINE void blend_color_color_float(float dst[4], const float src1[4], const fl
MINLINE void blend_color_hue_float(float dst[4], const float src1[4], const float src2[4])
{
const float fac = src2[3];
- if (fac != 0.0f && fac < 1.0f) {
+ if (fac != 0.0f) {
const float mfac = 1.0f - fac;
float h1, s1, v1;
float h2, s2, v2;
@@ -1107,7 +1107,7 @@ MINLINE void blend_color_hue_float(float dst[4], const float src1[4], const floa
MINLINE void blend_color_saturation_float(float dst[4], const float src1[4], const float src2[4])
{
const float fac = src2[3];
- if (fac != 0.0f && fac < 1.0f) {
+ if (fac != 0.0f) {
const float mfac = 1.0f - fac;
float h1, s1, v1;
float h2, s2, v2;
@@ -1134,7 +1134,7 @@ MINLINE void blend_color_saturation_float(float dst[4], const float src1[4], con
MINLINE void blend_color_luminosity_float(float dst[4], const float src1[4], const float src2[4])
{
const float fac = src2[3];
- if (fac != 0.0f && fac < 1.0f) {
+ if (fac != 0.0f) {
const float mfac = 1.0f - fac;
float h1, s1, v1;
float h2, s2, v2;
diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c
index e31659c35d9..c08329ef34f 100644
--- a/source/blender/blenlib/intern/storage.c
+++ b/source/blender/blenlib/intern/storage.c
@@ -37,7 +37,7 @@
#include <sys/stat.h>
-#if defined(__NetBSD__) || defined(__DragonFly__)
+#if defined(__NetBSD__) || defined(__DragonFly__) || defined(__HAIKU__)
/* Other modern unix os's should probably use this also */
# include <sys/statvfs.h>
# define USE_STATFS_STATVFS
diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h
index 00d00e98c84..0da15fe5bbc 100644
--- a/source/blender/blenloader/BLO_readfile.h
+++ b/source/blender/blenloader/BLO_readfile.h
@@ -119,14 +119,24 @@ void BLO_blendhandle_close(BlendHandle *bh);
bool BLO_has_bfile_extension(const char *str);
bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, char **r_name);
+/* Options controlling behavior of append/link code.
+ * Note: merged with 'user-level' options from operators etc. in 16 lower bits
+ * (see eFileSel_Params_Flag in DNA_space_types.h). */
+typedef enum BLO_LibLinkFlags {
+ /* Generate a placeholder (empty ID) if not found in current lib file. */
+ BLO_LIBLINK_USE_PLACEHOLDERS = 1 << 16,
+ /* Force loaded ID to be tagged as LIB_TAG_INDIRECT (used in reload context only). */
+ BLO_LIBLINK_FORCE_INDIRECT = 1 << 17,
+} BLO_LinkFlags;
+
struct Main *BLO_library_link_begin(struct Main *mainvar, BlendHandle **bh, const char *filepath);
struct ID *BLO_library_link_named_part(struct Main *mainl, BlendHandle **bh, const short idcode, const char *name);
struct ID *BLO_library_link_named_part_ex(
struct Main *mainl, BlendHandle **bh,
- const short idcode, const char *name, const short flag,
- struct Scene *scene, struct ViewLayer *view_layer,
- const bool use_placeholders, const bool force_indirect);
-void BLO_library_link_end(struct Main *mainl, BlendHandle **bh, short flag, struct Scene *scene, struct ViewLayer *view_layer);
+ const short idcode, const char *name, const int flag,
+ struct Scene *scene, struct ViewLayer *view_layer);
+void BLO_library_link_end(
+ struct Main *mainl, BlendHandle **bh, int flag, struct Scene *scene, struct ViewLayer *view_layer);
void BLO_library_link_copypaste(struct Main *mainl, BlendHandle *bh);
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 861952ff181..94f5f790f1c 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -136,6 +136,7 @@
#include "BKE_layer.h"
#include "BKE_library.h" // for which_libbase
#include "BKE_library_idmap.h"
+#include "BKE_library_override.h"
#include "BKE_library_query.h"
#include "BKE_idcode.h"
#include "BKE_idprop.h"
@@ -252,7 +253,9 @@ static void *read_struct(FileData *fd, BHead *bh, const char *blockname);
static void direct_link_modifiers(FileData *fd, ListBase *lb);
static BHead *find_bhead_from_code_name(FileData *fd, const short idcode, const char *name);
static BHead *find_bhead_from_idname(FileData *fd, const char *idname);
-static SceneCollection *get_scene_collection_active_or_create(struct Scene *scene, struct ViewLayer *view_layer, const short flag);
+static void expand_scene_collection(FileData *fd, Main *mainvar, SceneCollection *sc);
+static SceneCollection *get_scene_collection_active_or_create(
+ struct Scene *scene, struct ViewLayer *view_layer, const int flag);
/* this function ensures that reports are printed,
* in the case of libraray linking errors this is important!
@@ -2214,6 +2217,42 @@ static PreviewImage *direct_link_preview_image(FileData *fd, PreviewImage *old_p
/* ************ READ ID *************** */
+static void lib_link_id(FileData *fd, Main *main)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ int base_count, i;
+
+ base_count = set_listbasepointers(main, lbarray);
+
+ for (i = 0; i < base_count; i++) {
+ ListBase *lb = lbarray[i];
+ ID *id;
+
+ for (id = lb->first; id; id = id->next) {
+ if (id->override_static) {
+ id->override_static->reference = newlibadr_us(fd, id->lib, id->override_static->reference);
+ id->override_static->storage = newlibadr_us(fd, id->lib, id->override_static->storage);
+ }
+ }
+ }
+}
+
+static void direct_link_id_override_property_operation_cb(FileData *fd, void *data)
+{
+ IDOverrideStaticPropertyOperation *opop = data;
+
+ opop->subitem_reference_name = newdataadr(fd, opop->subitem_reference_name);
+ opop->subitem_local_name = newdataadr(fd, opop->subitem_local_name);
+}
+
+static void direct_link_id_override_property_cb(FileData *fd, void *data)
+{
+ IDOverrideStaticProperty *op = data;
+
+ op->rna_path = newdataadr(fd, op->rna_path);
+ link_list_ex(fd, &op->operations, direct_link_id_override_property_operation_cb);
+}
+
static void direct_link_id(FileData *fd, ID *id)
{
/*link direct data of ID properties*/
@@ -2223,6 +2262,12 @@ static void direct_link_id(FileData *fd, ID *id)
IDP_DirectLinkGroup_OrFree(&id->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
}
id->py_instance = NULL;
+
+ /* Link direct data of overrides. */
+ if (id->override_static) {
+ id->override_static = newdataadr(fd, id->override_static);
+ link_list_ex(fd, &id->override_static->properties, direct_link_id_override_property_cb);
+ }
}
/* ************ READ CurveMapping *************** */
@@ -2800,6 +2845,14 @@ static void lib_link_workspaces(FileData *fd, Main *bmain)
IDP_LibLinkProperty(id->properties, fd);
id_us_ensure_real(id);
+ for (WorkSpaceDataRelation *relation = workspace->scene_viewlayer_relations.first;
+ relation != NULL;
+ relation = relation->next)
+ {
+ relation->parent = newlibadr(fd, id->lib, relation->parent);
+ /* relation->value is set in direct_link_workspace_link_scene_data */
+ }
+
for (WorkSpaceLayout *layout = layouts->first, *layout_next; layout; layout = layout_next) {
bScreen *screen = newlibadr(fd, id->lib, BKE_workspace_layout_screen_get(layout));
@@ -2825,6 +2878,7 @@ static void direct_link_workspace(FileData *fd, WorkSpace *workspace, const Main
{
link_list(fd, BKE_workspace_layouts_get(workspace));
link_list(fd, &workspace->hook_layout_relations);
+ link_list(fd, &workspace->scene_viewlayer_relations);
link_list(fd, BKE_workspace_transform_orientations_get(workspace));
for (WorkSpaceDataRelation *relation = workspace->hook_layout_relations.first;
@@ -2838,7 +2892,7 @@ static void direct_link_workspace(FileData *fd, WorkSpace *workspace, const Main
if (ID_IS_LINKED(&workspace->id)) {
/* Appending workspace so render layer is likely from a different scene. Unset
* now, when activating workspace later we set a valid one from current scene. */
- BKE_workspace_view_layer_set(workspace, NULL);
+ BKE_workspace_relations_free(&workspace->scene_viewlayer_relations);
}
/* Same issue/fix as in direct_link_workspace_link_scene_data: Can't read workspace data
@@ -5466,11 +5520,6 @@ static void direct_link_object(FileData *fd, Object *ob)
/* weak weak... this was only meant as draw flag, now is used in give_base_to_objects too */
ob->flag &= ~OB_FROMGROUP;
- /* This is a transient flag; clear in order to avoid unneeded object update pending from
- * time when file was saved.
- */
- ob->recalc = 0;
-
/* XXX This should not be needed - but seems like it can happen in some cases, so for now play safe... */
ob->proxy_from = NULL;
@@ -5785,6 +5834,28 @@ static void lib_link_scene_collection(FileData *fd, Library *lib, SceneCollectio
}
}
+static void lib_link_view_layer(FileData *fd, Library *lib, ViewLayer *view_layer)
+{
+ /* tag scene layer to update for collection tree evaluation */
+ view_layer->flag |= VIEW_LAYER_ENGINE_DIRTY;
+
+ for (FreestyleModuleConfig *fmc = view_layer->freestyle_config.modules.first; fmc; fmc = fmc->next) {
+ fmc->script = newlibadr(fd, lib, fmc->script);
+ }
+
+ for (FreestyleLineSet *fls = view_layer->freestyle_config.linesets.first; fls; fls = fls->next) {
+ fls->linestyle = newlibadr_us(fd, lib, fls->linestyle);
+ fls->group = newlibadr_us(fd, lib, fls->group);
+ }
+
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ /* we only bump the use count for the collection objects */
+ base->object = newlibadr(fd, lib, base->object);
+ base->flag |= BASE_DIRTY_ENGINE_SETTINGS;
+ base->collection_properties = NULL;
+ }
+}
+
static void lib_link_scene(FileData *fd, Main *main)
{
#ifdef USE_SETSCENE_CHECK
@@ -5933,24 +6004,7 @@ static void lib_link_scene(FileData *fd, Main *main)
lib_link_scene_collection(fd, sce->id.lib, sce->collection);
for (ViewLayer *view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
- /* tag scene layer to update for collection tree evaluation */
- view_layer->flag |= VIEW_LAYER_ENGINE_DIRTY;
-
- for (FreestyleModuleConfig *fmc = view_layer->freestyle_config.modules.first; fmc; fmc = fmc->next) {
- fmc->script = newlibadr(fd, sce->id.lib, fmc->script);
- }
-
- for (FreestyleLineSet *fls = view_layer->freestyle_config.linesets.first; fls; fls = fls->next) {
- fls->linestyle = newlibadr_us(fd, sce->id.lib, fls->linestyle);
- fls->group = newlibadr_us(fd, sce->id.lib, fls->group);
- }
-
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- /* we only bump the use count for the collection objects */
- base->object = newlibadr(fd, sce->id.lib, base->object);
- base->flag |= BASE_DIRTY_ENGINE_SETTINGS;
- base->collection_properties = NULL;
- }
+ lib_link_view_layer(fd, sce->id.lib, view_layer);
}
#ifdef USE_SETSCENE_CHECK
@@ -6092,17 +6146,56 @@ static void direct_link_layer_collections(FileData *fd, ListBase *lb)
}
}
+static void direct_link_view_layer(FileData *fd, ViewLayer *view_layer)
+{
+ view_layer->stats = NULL;
+ link_list(fd, &view_layer->object_bases);
+ view_layer->basact = newdataadr(fd, view_layer->basact);
+ direct_link_layer_collections(fd, &view_layer->layer_collections);
+
+ if (view_layer->properties != NULL) {
+ view_layer->properties = newdataadr(fd, view_layer->properties);
+ BLI_assert(view_layer->properties != NULL);
+ IDP_DirectLinkGroup_OrFree(&view_layer->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ BKE_view_layer_engine_settings_validate_layer(view_layer);
+ }
+
+ view_layer->id_properties = newdataadr(fd, view_layer->id_properties);
+ IDP_DirectLinkGroup_OrFree(&view_layer->id_properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+
+ link_list(fd, &(view_layer->freestyle_config.modules));
+ link_list(fd, &(view_layer->freestyle_config.linesets));
+
+ view_layer->properties_evaluated = NULL;
+
+ BLI_listbase_clear(&view_layer->drawdata);
+}
+
/**
* Workspaces store a render layer pointer which can only be read after scene is read.
*/
static void direct_link_workspace_link_scene_data(
- FileData *fd, const Scene *scene, const ListBase *workspaces)
+ FileData *fd, Scene *scene, const ListBase *workspaces)
{
for (WorkSpace *workspace = workspaces->first; workspace; workspace = workspace->id.next) {
- ViewLayer *layer = newdataadr(fd, BKE_workspace_view_layer_get(workspace));
- /* only set when layer is from the scene we read */
- if (layer && (BLI_findindex(&scene->view_layers, layer) != -1)) {
- BKE_workspace_view_layer_set(workspace, layer);
+ for (WorkSpaceDataRelation *relation = workspace->scene_viewlayer_relations.first;
+ relation != NULL;
+ relation = relation->next)
+ {
+ ViewLayer *layer = newdataadr(fd, relation->value);
+ if (layer) {
+ BLI_assert(BLI_findindex(&scene->view_layers, layer) != -1);
+ /* relation->parent is set in lib_link_workspaces */
+ relation->value = layer;
+ }
+ }
+
+ if (workspace->view_layer) { /* this was temporariliy used during 2.8 project. Keep files compatible */
+ ViewLayer *layer = newdataadr(fd, workspace->view_layer);
+ /* only set when layer is from the scene we read */
+ if (layer && (BLI_findindex(&scene->view_layers, layer) != -1)) {
+ workspace->view_layer = layer;
+ }
}
}
}
@@ -6363,27 +6456,7 @@ static void direct_link_scene(FileData *fd, Scene *sce, Main *bmain)
/* insert into global old-new map for reading without UI (link_global accesses it again) */
link_glob_list(fd, &sce->view_layers);
for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
- view_layer->stats = NULL;
- link_list(fd, &view_layer->object_bases);
- view_layer->basact = newdataadr(fd, view_layer->basact);
- direct_link_layer_collections(fd, &view_layer->layer_collections);
-
- if (view_layer->properties != NULL) {
- view_layer->properties = newdataadr(fd, view_layer->properties);
- BLI_assert(view_layer->properties != NULL);
- IDP_DirectLinkGroup_OrFree(&view_layer->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
- BKE_view_layer_engine_settings_validate_layer(view_layer);
- }
-
- view_layer->id_properties = newdataadr(fd, view_layer->id_properties);
- IDP_DirectLinkGroup_OrFree(&view_layer->id_properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
-
- link_list(fd, &(view_layer->freestyle_config.modules));
- link_list(fd, &(view_layer->freestyle_config.linesets));
-
- view_layer->properties_evaluated = NULL;
-
- BLI_listbase_clear(&view_layer->drawdata);
+ direct_link_view_layer(fd, view_layer);
}
sce->collection_properties = newdataadr(fd, sce->collection_properties);
@@ -7046,6 +7119,8 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm)
wm->addonconf = NULL;
wm->userconf = NULL;
+ wm->message_bus = NULL;
+
BLI_listbase_clear(&wm->jobs);
BLI_listbase_clear(&wm->drags);
@@ -7476,7 +7551,7 @@ void blo_lib_link_restore(Main *newmain, wmWindowManager *curwm, Scene *curscene
for (WorkSpaceLayout *layout = layouts->first; layout; layout = layout->next) {
lib_link_workspace_layout_restore(id_map, newmain, layout);
}
- BKE_workspace_view_layer_set(workspace, cur_view_layer);
+ BKE_workspace_view_layer_set(workspace, cur_view_layer, curscene);
}
for (wmWindow *win = curwm->windows.first; win; win = win->next) {
@@ -7753,30 +7828,61 @@ static void direct_link_group(FileData *fd, Group *group)
link_list(fd, &group->gobject);
group->preview = direct_link_preview_image(fd, group->preview);
+
+ /* This runs before the very first doversion. */
+ if (group->collection != NULL) {
+ group->collection = newdataadr(fd, group->collection);
+ direct_link_scene_collection(fd, group->collection);
+ }
+
+ if (group->view_layer != NULL) {
+ group->view_layer = newdataadr(fd, group->view_layer);
+ direct_link_view_layer(fd, group->view_layer);
+ }
}
static void lib_link_group(FileData *fd, Main *main)
{
for (Group *group = main->group.first; group; group = group->id.next) {
if (group->id.tag & LIB_TAG_NEED_LINK) {
+ group->id.tag &= ~LIB_TAG_NEED_LINK;
IDP_LibLinkProperty(group->id.properties, fd);
-
- bool add_us = false;
-
- for (GroupObject *go = group->gobject.first; go; go = go->next) {
- go->ob = newlibadr_real_us(fd, group->id.lib, go->ob);
- if (go->ob) {
- go->ob->flag |= OB_FROMGROUP;
- /* if group has an object, it increments user... */
- add_us = true;
+
+ if (group->view_layer == NULL) {
+ /* Old file, this is required for doversion. */
+ bool add_us = false;
+
+ GroupObject *go, *gon;
+ go = group->gobject.first;
+ while (go) {
+ gon = go->next;
+ go->ob = newlibadr_real_us(fd, group->id.lib, go->ob);
+ if (go->ob != NULL) {
+ go->ob->flag |= OB_FROMGROUP;
+ /* If group has an object, it increments user... */
+ add_us = true;
+ }
+ else {
+ /* Remove NULL objects. */
+ BLI_remlink(&group->gobject, go);
+ MEM_freeN(go);
+ }
+ go = gon;
}
+
+ if (add_us) {
+ id_us_ensure_real(&group->id);
+ }
+ /* The rest of the read code is only for new files, skip it. */
+ continue;
}
- if (add_us) {
+
+ lib_link_scene_collection(fd, group->id.lib, group->collection);
+ lib_link_view_layer(fd, group->id.lib, group->view_layer);
+
+ if (!BLI_listbase_is_empty(&group->view_layer->object_bases)) {
id_us_ensure_real(&group->id);
}
- BKE_group_object_unlink(group, NULL); /* removes NULL entries */
-
- group->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -8708,6 +8814,8 @@ static void lib_link_all(FileData *fd, Main *main)
{
oldnewmap_sort(fd);
+ lib_link_id(fd, main);
+
/* No load UI for undo memfiles */
if (fd->memfile == NULL) {
lib_link_windowmanager(fd, main);
@@ -8933,6 +9041,12 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
BKE_main_id_tag_all(bfd->main, LIB_TAG_NEW, false);
+ /* Now that all our data-blocks are loaded, we can re-generate overrides from their references. */
+ if (fd->memfile == NULL) {
+ /* Do not apply in undo case! */
+ BKE_main_override_static_update(bfd->main);
+ }
+
lib_verify_nodetree(bfd->main, true);
fix_relpaths_library(fd->relabase, bfd->main); /* make all relative paths, relative to the open blend file */
@@ -9371,6 +9485,11 @@ static void expand_group(FileData *fd, Main *mainvar, Group *group)
for (go = group->gobject.first; go; go = go->next) {
expand_doit(fd, mainvar, go->ob);
}
+
+ if (group->collection != NULL) {
+ expand_scene_collection(fd, mainvar, group->collection);
+ }
+
}
static void expand_key(FileData *fd, Main *mainvar, Key *key)
@@ -10197,7 +10316,7 @@ static void give_base_to_objects(
scene_collection = get_scene_collection_active_or_create(scene, view_layer, FILE_ACTIVE_COLLECTION);
}
- BKE_collection_object_add(scene, scene_collection, ob);
+ BKE_collection_object_add(&scene->id, scene_collection, ob);
base = BKE_view_layer_base_find(view_layer, ob);
BKE_scene_object_base_flag_sync_from_base(base);
@@ -10239,7 +10358,7 @@ static void give_base_to_groups(
ob = BKE_object_add_only_object(mainvar, OB_EMPTY, group->id.name + 2);
ob->type = OB_EMPTY;
- BKE_collection_object_add(scene, scene_collection, ob);
+ BKE_collection_object_add(&scene->id, scene_collection, ob);
base = BKE_view_layer_base_find(view_layer, ob);
if (base->flag & BASE_SELECTABLED) {
@@ -10280,12 +10399,14 @@ static ID *create_placeholder(Main *mainvar, const short idcode, const char *idn
/* returns true if the item was found
* but it may already have already been appended/linked */
static ID *link_named_part(
- Main *mainl, FileData *fd, const short idcode, const char *name,
- const bool use_placeholders, const bool force_indirect)
+ Main *mainl, FileData *fd, const short idcode, const char *name, const int flag)
{
BHead *bhead = find_bhead_from_code_name(fd, idcode, name);
ID *id;
+ const bool use_placeholders = (flag & BLO_LIBLINK_USE_PLACEHOLDERS) != 0;
+ const bool force_indirect = (flag & BLO_LIBLINK_FORCE_INDIRECT) != 0;
+
BLI_assert(BKE_idcode_is_linkable(idcode) && BKE_idcode_is_valid(idcode));
if (bhead) {
@@ -10325,7 +10446,8 @@ static ID *link_named_part(
return id;
}
-static SceneCollection *get_scene_collection_active_or_create(struct Scene *scene, struct ViewLayer *view_layer, const short flag)
+static SceneCollection *get_scene_collection_active_or_create(
+ struct Scene *scene, struct ViewLayer *view_layer, const int flag)
{
LayerCollection *lc = NULL;
@@ -10333,14 +10455,14 @@ static SceneCollection *get_scene_collection_active_or_create(struct Scene *scen
lc = BKE_layer_collection_get_active_ensure(scene, view_layer);
}
else {
- SceneCollection *sc = BKE_collection_add(scene, NULL, NULL);
+ SceneCollection *sc = BKE_collection_add(&scene->id, NULL, COLLECTION_TYPE_NONE, NULL);
lc = BKE_collection_link(view_layer, sc);
}
return lc->scene_collection;
}
-static void link_object_postprocess(ID *id, Scene *scene, ViewLayer *view_layer, const short flag)
+static void link_object_postprocess(ID *id, Scene *scene, ViewLayer *view_layer, const int flag)
{
if (scene) {
/* link to scene */
@@ -10352,7 +10474,7 @@ static void link_object_postprocess(ID *id, Scene *scene, ViewLayer *view_layer,
ob->mode = OB_MODE_OBJECT;
sc = get_scene_collection_active_or_create(scene, view_layer, flag);
- BKE_collection_object_add(scene, sc, ob);
+ BKE_collection_object_add(&scene->id, sc, ob);
base = BKE_view_layer_base_find(view_layer, ob);
BKE_scene_object_base_flag_sync_from_base(base);
@@ -10402,10 +10524,10 @@ void BLO_library_link_copypaste(Main *mainl, BlendHandle *bh)
}
static ID *link_named_part_ex(
- Main *mainl, FileData *fd, const short idcode, const char *name, const short flag,
- Scene *scene, ViewLayer *view_layer, const bool use_placeholders, const bool force_indirect)
+ Main *mainl, FileData *fd, const short idcode, const char *name, const int flag,
+ Scene *scene, ViewLayer *view_layer)
{
- ID *id = link_named_part(mainl, fd, idcode, name, use_placeholders, force_indirect);
+ ID *id = link_named_part(mainl, fd, idcode, name, flag);
if (id && (GS(id->name) == ID_OB)) { /* loose object: give a base */
link_object_postprocess(id, scene, view_layer, flag);
@@ -10431,7 +10553,7 @@ static ID *link_named_part_ex(
ID *BLO_library_link_named_part(Main *mainl, BlendHandle **bh, const short idcode, const char *name)
{
FileData *fd = (FileData*)(*bh);
- return link_named_part(mainl, fd, idcode, name, false, false);
+ return link_named_part(mainl, fd, idcode, name, 0);
}
/**
@@ -10445,18 +10567,15 @@ ID *BLO_library_link_named_part(Main *mainl, BlendHandle **bh, const short idcod
* \param flag Options for linking, used for instantiating.
* \param scene The scene in which to instantiate objects/groups (if NULL, no instantiation is done).
* \param v3d The active View3D (only to define active layers for instantiated objects & groups, can be NULL).
- * \param use_placeholders If true, generate a placeholder (empty ID) if not found in current lib file.
- * \param force_indirect If true, force loaded ID to be tagged as LIB_TAG_INDIRECT (used in reload context only).
* \return the linked ID when found.
*/
ID *BLO_library_link_named_part_ex(
Main *mainl, BlendHandle **bh,
- const short idcode, const char *name, const short flag,
- Scene *scene, ViewLayer *view_layer,
- const bool use_placeholders, const bool force_indirect)
+ const short idcode, const char *name, const int flag,
+ Scene *scene, ViewLayer *view_layer)
{
FileData *fd = (FileData*)(*bh);
- return link_named_part_ex(mainl, fd, idcode, name, flag, scene, view_layer, use_placeholders, force_indirect);
+ return link_named_part_ex(mainl, fd, idcode, name, flag, scene, view_layer);
}
static void link_id_part(ReportList *reports, FileData *fd, Main *mainvar, ID *id, ID **r_id)
@@ -10656,7 +10775,7 @@ static void library_link_end(Main *mainl, FileData **fd, const short flag, Scene
* \param scene The scene in which to instantiate objects/groups (if NULL, no instantiation is done).
* \param view_layer The scene layer in which to instantiate objects/groups (if NULL, no instantiation is done).
*/
-void BLO_library_link_end(Main *mainl, BlendHandle **bh, short flag, Scene *scene, ViewLayer *view_layer)
+void BLO_library_link_end(Main *mainl, BlendHandle **bh, int flag, Scene *scene, ViewLayer *view_layer)
{
FileData *fd = (FileData*)(*bh);
library_link_end(mainl, &fd, flag, scene, view_layer);
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index b945f5bdcd3..bf2d5c8e326 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -62,6 +62,8 @@
#include "BKE_animsys.h"
#include "BKE_brush.h"
#include "BKE_colortools.h"
+#include "BKE_fcurve.h"
+#include "BKE_gpencil.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_mask.h"
@@ -71,7 +73,6 @@
#include "BKE_sequencer.h"
#include "BKE_screen.h"
#include "BKE_tracking.h"
-#include "BKE_gpencil.h"
#include "BLI_math.h"
#include "BLI_listbase.h"
@@ -285,6 +286,67 @@ static void do_versions_compositor_render_passes(bNodeTree *ntree)
}
}
+
+static char *replace_bbone_easing_rnapath(char *old_path)
+{
+ char *new_path = NULL;
+
+ /* NOTE: This will break paths for any bones/custom-properties
+ * which happen be named after the bbone property id's
+ */
+ if (strstr(old_path, "bbone_in"))
+ new_path = BLI_str_replaceN(old_path, "bbone_in", "bbone_easein");
+ else if (strstr(old_path, "bbone_out"))
+ new_path = BLI_str_replaceN(old_path, "bbone_out", "bbone_easeout");
+
+ if (new_path) {
+ MEM_freeN(old_path);
+ return new_path;
+ }
+ else {
+ return old_path;
+ }
+}
+
+static void do_version_bbone_easing_fcurve_fix(ID *UNUSED(id), FCurve *fcu, void *UNUSED(user_data))
+{
+ /* F-Curve's path (for bbone_in/out) */
+ if (fcu->rna_path) {
+ fcu->rna_path = replace_bbone_easing_rnapath(fcu->rna_path);
+ }
+
+ /* Driver -> Driver Vars (for bbone_in/out) */
+ if (fcu->driver) {
+ for (DriverVar *dvar = fcu->driver->variables.first; dvar; dvar = dvar->next) {
+ DRIVER_TARGETS_LOOPER(dvar)
+ {
+ if (dtar->rna_path) {
+ dtar->rna_path = replace_bbone_easing_rnapath(dtar->rna_path);
+ }
+ }
+ DRIVER_TARGETS_LOOPER_END;
+ }
+ }
+
+ /* FModifiers -> Stepped (for frame_start/end) */
+ if (fcu->modifiers.first) {
+ for (FModifier *fcm = fcu->modifiers.first; fcm; fcm = fcm->next) {
+ if (fcm->type == FMODIFIER_TYPE_STEPPED) {
+ FMod_Stepped *data = fcm->data;
+
+ /* Modifier doesn't work if the modifier's copy of start/end frame are both 0
+ * as those were only getting written to the fcm->data copy (T52009)
+ */
+ if ((fcm->sfra == fcm->efra) && (fcm->sfra == 0)) {
+ fcm->sfra = data->start_frame;
+ fcm->efra = data->end_frame;
+ }
+ }
+ }
+ }
+}
+
+
void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
{
if (!MAIN_VERSION_ATLEAST(main, 270, 0)) {
@@ -1742,4 +1804,10 @@ void do_versions_after_linking_270(Main *main)
}
} FOREACH_NODETREE_END
}
+
+ if (!MAIN_VERSION_ATLEAST(main, 279, 2)) {
+ /* B-Bones (bbone_in/out -> bbone_easein/out) + Stepped FMod Frame Start/End fix */
+ /* if (!DNA_struct_elem_find(fd->filesdna, "Bone", "float", "bbone_easein")) */
+ BKE_fcurves_main_cb(main, do_version_bbone_easing_fcurve_fix, NULL);
+ }
}
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index 00d578918fa..84aab78ff18 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -39,8 +39,10 @@
#include "DNA_object_types.h"
#include "DNA_camera_types.h"
#include "DNA_gpu_types.h"
+#include "DNA_group_types.h"
#include "DNA_lamp_types.h"
#include "DNA_layer_types.h"
+#include "DNA_lightprobe_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_scene_types.h"
@@ -52,6 +54,7 @@
#include "BKE_collection.h"
#include "BKE_customdata.h"
#include "BKE_freestyle.h"
+#include "BKE_group.h"
#include "BKE_idprop.h"
#include "BKE_layer.h"
#include "BKE_main.h"
@@ -87,8 +90,9 @@ static void do_version_workspaces_create_from_screens(Main *bmain)
{
for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
const bScreen *screen_parent = screen_parent_find(screen);
+ Scene *scene = screen->scene;
WorkSpace *workspace;
- ViewLayer *layer = BKE_view_layer_from_scene_get(screen->scene);
+ ViewLayer *layer = BKE_view_layer_from_scene_get(scene);
ListBase *transform_orientations;
if (screen_parent) {
@@ -101,7 +105,7 @@ static void do_version_workspaces_create_from_screens(Main *bmain)
workspace = BKE_workspace_add(bmain, screen->id.name + 2);
}
BKE_workspace_layout_add(workspace, screen, screen->id.name + 2);
- BKE_workspace_view_layer_set(workspace, layer);
+ BKE_workspace_view_layer_set(workspace, layer, scene);
#ifdef WITH_CLAY_ENGINE
BLI_strncpy(workspace->view_render.engine_id, RE_engine_id_BLENDER_CLAY,
@@ -112,7 +116,7 @@ static void do_version_workspaces_create_from_screens(Main *bmain)
#endif
transform_orientations = BKE_workspace_transform_orientations_get(workspace);
- BLI_duplicatelist(transform_orientations, &screen->scene->transform_spaces);
+ BLI_duplicatelist(transform_orientations, &scene->transform_spaces);
}
}
@@ -171,7 +175,7 @@ void do_versions_after_linking_280(Main *main)
for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
/* since we don't have access to FileData we check the (always valid) first render layer instead */
if (scene->view_layers.first == NULL) {
- SceneCollection *sc_master = BKE_collection_master(scene);
+ SceneCollection *sc_master = BKE_collection_master(&scene->id);
BLI_strncpy(sc_master->name, "Master Collection", sizeof(sc_master->name));
struct DoVersionSceneCollections {
@@ -217,7 +221,7 @@ void do_versions_after_linking_280(Main *main)
if (base->lay & (1 << layer)) {
int collection_index = -1;
if ((base->object->restrictflag & OB_RESTRICT_VIEW) &&
- (base->object->restrictflag & OB_RESTRICT_RENDER))
+ (base->object->restrictflag & OB_RESTRICT_RENDER))
{
collection_index = DO_VERSION_COLLECTION_HIDE_ALL;
}
@@ -242,7 +246,7 @@ void do_versions_after_linking_280(Main *main)
layer + 1,
collections[DO_VERSION_COLLECTION_VISIBLE].suffix);
collections[DO_VERSION_COLLECTION_VISIBLE].collections[layer] =
- BKE_collection_add(scene, sc_master, name);
+ BKE_collection_add(&scene->id, sc_master, COLLECTION_TYPE_NONE, name);
collections[DO_VERSION_COLLECTION_VISIBLE].created |= (1 << layer);
}
@@ -254,12 +258,17 @@ void do_versions_after_linking_280(Main *main)
"Collection %d%s",
layer + 1,
collections[collection_index].suffix);
- collections[collection_index].collections[layer] = BKE_collection_add(scene, sc_parent, name);
+ collections[collection_index].collections[layer] = BKE_collection_add(
+ &scene->id,
+ sc_parent,
+ COLLECTION_TYPE_NONE,
+ name);
collections[collection_index].created |= (1 << layer);
}
}
- BKE_collection_object_add(scene, collections[collection_index].collections[layer], base->object);
+ BKE_collection_object_add(
+ &scene->id, collections[collection_index].collections[layer], base->object);
}
if (base->flag & SELECT) {
@@ -281,18 +290,20 @@ void do_versions_after_linking_280(Main *main)
(collections[DO_VERSION_COLLECTION_HIDE].collections[layer] !=
scene_collection_parent->scene_collections.first))
{
- BLI_listbase_swaplinks(&scene_collection_parent->scene_collections,
- collections[DO_VERSION_COLLECTION_HIDE].collections[layer],
- scene_collection_parent->scene_collections.first);
+ BLI_listbase_swaplinks(
+ &scene_collection_parent->scene_collections,
+ collections[DO_VERSION_COLLECTION_HIDE].collections[layer],
+ scene_collection_parent->scene_collections.first);
}
if ((collections[DO_VERSION_COLLECTION_HIDE_ALL].created & (1 << layer)) &&
(collections[DO_VERSION_COLLECTION_HIDE_ALL].collections[layer] !=
scene_collection_parent->scene_collections.last))
{
- BLI_listbase_swaplinks(&scene_collection_parent->scene_collections,
- collections[DO_VERSION_COLLECTION_HIDE_ALL].collections[layer],
- scene_collection_parent->scene_collections.last);
+ BLI_listbase_swaplinks(
+ &scene_collection_parent->scene_collections,
+ collections[DO_VERSION_COLLECTION_HIDE_ALL].collections[layer],
+ scene_collection_parent->scene_collections.last);
}
scene_collection_parent = scene_collection_parent->next;
@@ -312,18 +323,18 @@ void do_versions_after_linking_280(Main *main)
/* It is up to the external engine to handle
* its own doversion in this case. */
BKE_override_view_layer_int_add(
- view_layer,
- ID_SCE,
- "samples",
- srl->samples);
+ view_layer,
+ ID_SCE,
+ "samples",
+ srl->samples);
}
if (srl->mat_override) {
BKE_override_view_layer_datablock_add(
- view_layer,
- ID_MA,
- "self",
- (ID *)srl->mat_override);
+ view_layer,
+ ID_MA,
+ "self",
+ (ID *)srl->mat_override);
}
if (srl->layflag & SCE_LAY_DISABLE) {
@@ -351,28 +362,29 @@ void do_versions_after_linking_280(Main *main)
/* Add new collection bases. */
for (int layer = 0; layer < 20; layer++) {
if ((scene->lay & srl->lay & ~(srl->lay_exclude) & (1 << layer)) ||
- (srl->lay_zmask & (scene->lay | srl->lay_exclude) & (1 << layer)))
+ (srl->lay_zmask & (scene->lay | srl->lay_exclude) & (1 << layer)))
{
if (collections[DO_VERSION_COLLECTION_VISIBLE].created & (1 << layer)) {
LayerCollection *layer_collection_parent;
- layer_collection_parent = BKE_collection_link(view_layer,
- collections[DO_VERSION_COLLECTION_VISIBLE].collections[layer]);
+ layer_collection_parent = BKE_collection_link(
+ view_layer,
+ collections[DO_VERSION_COLLECTION_VISIBLE].collections[layer]);
if (srl->lay_zmask & (1 << layer)) {
BKE_override_layer_collection_boolean_add(
- layer_collection_parent,
- ID_OB,
- "cycles.is_holdout",
- true);
+ layer_collection_parent,
+ ID_OB,
+ "cycles.is_holdout",
+ true);
}
if ((srl->lay & (1 << layer)) == 0) {
BKE_override_layer_collection_boolean_add(
- layer_collection_parent,
- ID_OB,
- "cycles_visibility.camera",
- false);
+ layer_collection_parent,
+ ID_OB,
+ "cycles_visibility.camera",
+ false);
}
LayerCollection *layer_collection_child;
@@ -380,7 +392,8 @@ void do_versions_after_linking_280(Main *main)
for (int j = 1; j < 4; j++) {
if (collections[j].created & (1 << layer)) {
- layer_collection_child->flag = collections[j].flag_render & (~COLLECTION_DISABLED);
+ layer_collection_child->flag =
+ collections[j].flag_render & (~COLLECTION_DISABLED);
if (collections[j].flag_render & COLLECTION_DISABLED) {
BKE_collection_disable(view_layer, layer_collection_child);
@@ -429,7 +442,8 @@ void do_versions_after_linking_280(Main *main)
/* If layer was not set, disable it. */
LayerCollection *layer_collection_parent;
- layer_collection_parent = ((LayerCollection *)view_layer->layer_collections.first)->layer_collections.first;
+ layer_collection_parent =
+ ((LayerCollection *)view_layer->layer_collections.first)->layer_collections.first;
for (int layer = 0; layer < 20; layer++) {
if (collections[DO_VERSION_COLLECTION_VISIBLE].created & (1 << layer)) {
@@ -475,7 +489,7 @@ void do_versions_after_linking_280(Main *main)
}
/* Fallback name if only one layer was found in the original file */
- if (BLI_listbase_count_ex(&sc_master->scene_collections, 2) == 1) {
+ if (BLI_listbase_is_single(&sc_master->scene_collections)) {
BKE_collection_rename(scene, sc_master->scene_collections.first, "Default Collection");
}
@@ -553,6 +567,59 @@ void do_versions_after_linking_280(Main *main)
}
}
}
+
+ {
+ for (WorkSpace *workspace = main->workspaces.first; workspace; workspace = workspace->id.next) {
+ if (workspace->view_layer) {
+ /* During 2.8 work we temporarly stored view-layer in the
+ * workspace directly, but should be stored there per-scene. */
+ for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ if (BLI_findindex(&scene->view_layers, workspace->view_layer) != -1) {
+ BKE_workspace_view_layer_set(workspace, workspace->view_layer, scene);
+ workspace->view_layer = NULL;
+ }
+ }
+ }
+ BLI_assert(workspace->view_layer == NULL);
+ }
+ }
+
+ {
+ /* Since we don't have access to FileData we check the (always valid) master collection of the group. */
+ for (Group *group = main->group.first; group; group = group->id.next) {
+ if (group->collection == NULL) {
+ BKE_group_init(group);
+ SceneCollection *sc = GROUP_MASTER_COLLECTION(group);
+ SceneCollection *sc_hidden = NULL;
+
+ for (GroupObject *go = group->gobject.first; go; go = go->next) {
+ if (go->ob->lay & group->layer) {
+ BKE_collection_object_add(&group->id, sc, go->ob);
+ }
+ else {
+ if (sc_hidden == NULL) {
+ sc_hidden = BKE_collection_add(&group->id, sc, COLLECTION_TYPE_GROUP_INTERNAL, "Hidden");
+ }
+ BKE_collection_object_add(&group->id, sc_hidden, go->ob);
+ }
+ }
+
+ if (sc_hidden != NULL) {
+ LayerCollection *layer_collection_master, *layer_collection_hidden;
+
+ layer_collection_master = group->view_layer->layer_collections.first;
+ layer_collection_hidden = layer_collection_master->layer_collections.first;
+
+ layer_collection_hidden->flag &= ~COLLECTION_VISIBLE;
+ }
+ }
+
+ GroupObject *go;
+ while ((go = BLI_pophead(&group->gobject))) {
+ MEM_freeN(go);
+ }
+ }
+ }
}
static void do_version_layer_collections_idproperties(ListBase *lb)
@@ -682,6 +749,13 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
+ if (!DNA_struct_elem_find(fd->filesdna, "LightProbe", "float", "vis_bias")) {
+ for (LightProbe *probe = main->lightprobe.first; probe; probe = probe->id.next) {
+ probe->vis_bias = 1.0f;
+ probe->vis_blur = 0.2f;
+ }
+ }
+
typedef enum eNTreeDoVersionErrors {
NTREE_DOVERSION_NO_ERROR = 0,
NTREE_DOVERSION_NEED_OUTPUT = (1 << 0),
diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c
index 36c524796ce..156a6e3d1c0 100644
--- a/source/blender/blenloader/intern/versioning_legacy.c
+++ b/source/blender/blenloader/intern/versioning_legacy.c
@@ -1871,7 +1871,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
BKE_pose_tag_recalc(main, ob->pose);
/* cannot call stuff now (pointers!), done in setup_app_data */
- ob->recalc |= OB_RECALC_OB|OB_RECALC_DATA|OB_RECALC_TIME;
+ ob->id.tag |= LIB_TAG_ID_RECALC_ALL;
/* new generic xray option */
arm = blo_do_versions_newlibadr(fd, lib, ob->data);
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 90f15d41408..0f9f509bfde 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -168,8 +168,10 @@
#include "BKE_curve.h"
#include "BKE_constraint.h"
#include "BKE_global.h" // for G
+#include "BKE_group.h"
#include "BKE_idcode.h"
#include "BKE_library.h" // for set_listbasepointers
+#include "BKE_library_override.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_report.h"
@@ -683,6 +685,25 @@ static void write_iddata(void *wd, const ID *id)
if (id->properties && !ELEM(GS(id->name), ID_WM)) {
IDP_WriteProperty(id->properties, wd);
}
+
+ if (id->override_static) {
+ writestruct(wd, DATA, IDOverrideStatic, 1, id->override_static);
+
+ writelist(wd, DATA, IDOverrideStaticProperty, &id->override_static->properties);
+ for (IDOverrideStaticProperty *op = id->override_static->properties.first; op; op = op->next) {
+ writedata(wd, DATA, strlen(op->rna_path) + 1, op->rna_path);
+
+ writelist(wd, DATA, IDOverrideStaticPropertyOperation, &op->operations);
+ for (IDOverrideStaticPropertyOperation *opop = op->operations.first; opop; opop = opop->next) {
+ if (opop->subitem_reference_name) {
+ writedata(wd, DATA, strlen(opop->subitem_reference_name) + 1, opop->subitem_reference_name);
+ }
+ if (opop->subitem_local_name) {
+ writedata(wd, DATA, strlen(opop->subitem_local_name) + 1, opop->subitem_local_name);
+ }
+ }
+ }
+ }
}
static void write_previews(WriteData *wd, const PreviewImage *prv_orig)
@@ -1118,7 +1139,7 @@ static void current_screen_compat(
*r_screen = (window) ? BKE_workspace_active_screen_get(window->workspace_hook) : NULL;
*r_scene = (window) ? window->scene : NULL;
- *r_render_layer = (window) ? BKE_workspace_view_layer_get(workspace) : NULL;
+ *r_render_layer = (window) ? BKE_workspace_view_layer_get(workspace, *r_scene) : NULL;
}
typedef struct RenderInfo {
@@ -1328,9 +1349,13 @@ static void write_particlesettings(WriteData *wd, ParticleSettings *part)
if (dw->ob != NULL) {
dw->index = 0;
if (part->dup_group) { /* can be NULL if lining fails or set to None */
- for (GroupObject *go = part->dup_group->gobject.first;
- go && go->ob != dw->ob;
- go = go->next, dw->index++);
+ FOREACH_GROUP_OBJECT(part->dup_group, object)
+ {
+ if (object != dw->ob) {
+ dw->index++;
+ }
+ }
+ FOREACH_GROUP_OBJECT_END
}
}
writestruct(wd, DATA, ParticleDupliWeight, 1, dw);
@@ -2592,6 +2617,28 @@ static void write_layer_collections(WriteData *wd, ListBase *lb)
}
}
+static void write_view_layer(WriteData *wd, ViewLayer *view_layer)
+{
+ writestruct(wd, DATA, ViewLayer, 1, view_layer);
+ writelist(wd, DATA, Base, &view_layer->object_bases);
+ if (view_layer->properties) {
+ IDP_WriteProperty(view_layer->properties, wd);
+ }
+
+ if (view_layer->id_properties) {
+ IDP_WriteProperty(view_layer->id_properties, wd);
+ }
+
+ for (FreestyleModuleConfig *fmc = view_layer->freestyle_config.modules.first; fmc; fmc = fmc->next) {
+ writestruct(wd, DATA, FreestyleModuleConfig, 1, fmc);
+ }
+
+ for (FreestyleLineSet *fls = view_layer->freestyle_config.linesets.first; fls; fls = fls->next) {
+ writestruct(wd, DATA, FreestyleLineSet, 1, fls);
+ }
+ write_layer_collections(wd, &view_layer->layer_collections);
+}
+
static void write_scene(WriteData *wd, Scene *sce)
{
/* write LibData */
@@ -2688,6 +2735,9 @@ static void write_scene(WriteData *wd, Scene *sce)
case SEQ_TYPE_TEXT:
writestruct(wd, DATA, TextVars, 1, seq->effectdata);
break;
+ case SEQ_TYPE_COLORMIX:
+ writestruct(wd, DATA, ColorMixVars, 1, seq->effectdata);
+ break;
}
}
@@ -2772,26 +2822,7 @@ static void write_scene(WriteData *wd, Scene *sce)
write_scene_collection(wd, sce->collection);
for (ViewLayer *view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
- writestruct(wd, DATA, ViewLayer, 1, view_layer);
- writelist(wd, DATA, Base, &view_layer->object_bases);
-
- if (view_layer->properties) {
- IDP_WriteProperty(view_layer->properties, wd);
- }
-
- if (view_layer->id_properties) {
- IDP_WriteProperty(view_layer->id_properties, wd);
- }
-
- for (FreestyleModuleConfig *fmc = view_layer->freestyle_config.modules.first; fmc; fmc = fmc->next) {
- writestruct(wd, DATA, FreestyleModuleConfig, 1, fmc);
- }
-
- for (FreestyleLineSet *fls = view_layer->freestyle_config.linesets.first; fls; fls = fls->next) {
- writestruct(wd, DATA, FreestyleLineSet, 1, fls);
- }
-
- write_layer_collections(wd, &view_layer->layer_collections);
+ write_view_layer(wd, view_layer);
}
if (sce->layer_properties) {
@@ -3225,10 +3256,8 @@ static void write_group(WriteData *wd, Group *group)
write_iddata(wd, &group->id);
write_previews(wd, group->preview);
-
- for (GroupObject *go = group->gobject.first; go; go = go->next) {
- writestruct(wd, DATA, GroupObject, 1, go);
- }
+ write_scene_collection(wd, group->collection);
+ write_view_layer(wd, group->view_layer);
}
}
@@ -3770,6 +3799,7 @@ static void write_workspace(WriteData *wd, WorkSpace *workspace)
writestruct(wd, ID_WS, WorkSpace, 1, workspace);
writelist(wd, DATA, WorkSpaceLayout, layouts);
writelist(wd, DATA, WorkSpaceDataRelation, &workspace->hook_layout_relations);
+ writelist(wd, DATA, WorkSpaceDataRelation, &workspace->scene_viewlayer_relations);
writelist(wd, DATA, TransformOrientation, transform_orientations);
}
@@ -3804,6 +3834,8 @@ static void write_libraries(WriteData *wd, Main *main)
/* XXX needs rethink, just like save UI in undo files now - would be nice to append things only for the]
* quit.blend and temp saves */
if (found_one) {
+ /* Not overridable. */
+
writestruct(wd, ID_LI, Library, 1, main->curlib);
write_iddata(wd, &main->curlib->id);
@@ -3938,137 +3970,159 @@ static bool write_file_handle(
* avoid thumbnail detecting changes because of this. */
mywrite_flush(wd);
- ListBase *lbarray[MAX_LIBARRAY];
- int a = set_listbasepointers(mainvar, lbarray);
- while (a--) {
- ID *id = lbarray[a]->first;
+ OverrideStaticStorage *override_storage = !wd->current ? BKE_override_static_operations_store_initialize() : NULL;
- if (id && GS(id->name) == ID_LI) {
- continue; /* Libraries are handled separately below. */
- }
+ /* This outer loop allows to save first datablocks from real mainvar, then the temp ones from override process,
+ * if needed, without duplicating whole code. */
+ Main *bmain = mainvar;
+ do {
+ ListBase *lbarray[MAX_LIBARRAY];
+ int a = set_listbasepointers(bmain, lbarray);
+ while (a--) {
+ ID *id = lbarray[a]->first;
- for (; id; id = id->next) {
- /* We should never attempt to write non-regular IDs (i.e. all kind of temp/runtime ones). */
- BLI_assert((id->tag & (LIB_TAG_NO_MAIN | LIB_TAG_NO_USER_REFCOUNT | LIB_TAG_NOT_ALLOCATED)) == 0);
+ if (id && GS(id->name) == ID_LI) {
+ continue; /* Libraries are handled separately below. */
+ }
- switch ((ID_Type)GS(id->name)) {
- case ID_WM:
- write_windowmanager(wd, (wmWindowManager *)id);
- break;
- case ID_WS:
- write_workspace(wd, (WorkSpace *)id);
- break;
- case ID_SCR:
- write_screen(wd, (bScreen *)id);
- break;
- case ID_MC:
- write_movieclip(wd, (MovieClip *)id);
- break;
- case ID_MSK:
- write_mask(wd, (Mask *)id);
- break;
- case ID_SCE:
- write_scene(wd, (Scene *)id);
- break;
- case ID_CU:
- write_curve(wd, (Curve *)id);
- break;
- case ID_MB:
- write_mball(wd, (MetaBall *)id);
- break;
- case ID_IM:
- write_image(wd, (Image *)id);
- break;
- case ID_CA:
- write_camera(wd, (Camera *)id);
- break;
- case ID_LA:
- write_lamp(wd, (Lamp *)id);
- break;
- case ID_LT:
- write_lattice(wd, (Lattice *)id);
- break;
- case ID_VF:
- write_vfont(wd, (VFont *)id);
- break;
- case ID_KE:
- write_key(wd, (Key *)id);
- break;
- case ID_WO:
- write_world(wd, (World *)id);
- break;
- case ID_TXT:
- write_text(wd, (Text *)id);
- break;
- case ID_SPK:
- write_speaker(wd, (Speaker *)id);
- break;
- case ID_LP:
- write_probe(wd, (LightProbe *)id);
- break;
- case ID_SO:
- write_sound(wd, (bSound *)id);
- break;
- case ID_GR:
- write_group(wd, (Group *)id);
- break;
- case ID_AR:
- write_armature(wd, (bArmature *)id);
- break;
- case ID_AC:
- write_action(wd, (bAction *)id);
- break;
- case ID_OB:
- write_object(wd, (Object *)id);
- break;
- case ID_MA:
- write_material(wd, (Material *)id);
- break;
- case ID_TE:
- write_texture(wd, (Tex *)id);
- break;
- case ID_ME:
- write_mesh(wd, (Mesh *)id);
- break;
- case ID_PA:
- write_particlesettings(wd, (ParticleSettings *)id);
- break;
- case ID_NT:
- write_nodetree(wd, (bNodeTree *)id);
- break;
- case ID_BR:
- write_brush(wd, (Brush *)id);
- break;
- case ID_PAL:
- write_palette(wd, (Palette *)id);
- break;
- case ID_PC:
- write_paintcurve(wd, (PaintCurve *)id);
- break;
- case ID_GD:
- write_gpencil(wd, (bGPdata *)id);
- break;
- case ID_LS:
- write_linestyle(wd, (FreestyleLineStyle *)id);
- break;
- case ID_CF:
- write_cachefile(wd, (CacheFile *)id);
- break;
- case ID_LI:
- /* Do nothing, handled below - and should never be reached. */
- BLI_assert(0);
- break;
- case ID_IP:
- /* Do nothing, deprecated. */
- break;
- default:
- /* Should never be reached. */
- BLI_assert(0);
- break;
+ for (; id; id = id->next) {
+ /* We should never attempt to write non-regular IDs (i.e. all kind of temp/runtime ones). */
+ BLI_assert((id->tag & (LIB_TAG_NO_MAIN | LIB_TAG_NO_USER_REFCOUNT | LIB_TAG_NOT_ALLOCATED)) == 0);
+
+ const bool do_override = !ELEM(override_storage, NULL, bmain) && id->override_static;
+
+ if (do_override) {
+ BKE_override_static_operations_store_start(override_storage, id);
+ }
+
+ switch ((ID_Type)GS(id->name)) {
+ case ID_WM:
+ write_windowmanager(wd, (wmWindowManager *)id);
+ break;
+ case ID_WS:
+ write_workspace(wd, (WorkSpace *)id);
+ break;
+ case ID_SCR:
+ write_screen(wd, (bScreen *)id);
+ break;
+ case ID_MC:
+ write_movieclip(wd, (MovieClip *)id);
+ break;
+ case ID_MSK:
+ write_mask(wd, (Mask *)id);
+ break;
+ case ID_SCE:
+ write_scene(wd, (Scene *)id);
+ break;
+ case ID_CU:
+ write_curve(wd, (Curve *)id);
+ break;
+ case ID_MB:
+ write_mball(wd, (MetaBall *)id);
+ break;
+ case ID_IM:
+ write_image(wd, (Image *)id);
+ break;
+ case ID_CA:
+ write_camera(wd, (Camera *)id);
+ break;
+ case ID_LA:
+ write_lamp(wd, (Lamp *)id);
+ break;
+ case ID_LT:
+ write_lattice(wd, (Lattice *)id);
+ break;
+ case ID_VF:
+ write_vfont(wd, (VFont *)id);
+ break;
+ case ID_KE:
+ write_key(wd, (Key *)id);
+ break;
+ case ID_WO:
+ write_world(wd, (World *)id);
+ break;
+ case ID_TXT:
+ write_text(wd, (Text *)id);
+ break;
+ case ID_SPK:
+ write_speaker(wd, (Speaker *)id);
+ break;
+ case ID_LP:
+ write_probe(wd, (LightProbe *)id);
+ break;
+ case ID_SO:
+ write_sound(wd, (bSound *)id);
+ break;
+ case ID_GR:
+ write_group(wd, (Group *)id);
+ break;
+ case ID_AR:
+ write_armature(wd, (bArmature *)id);
+ break;
+ case ID_AC:
+ write_action(wd, (bAction *)id);
+ break;
+ case ID_OB:
+ write_object(wd, (Object *)id);
+ break;
+ case ID_MA:
+ write_material(wd, (Material *)id);
+ break;
+ case ID_TE:
+ write_texture(wd, (Tex *)id);
+ break;
+ case ID_ME:
+ write_mesh(wd, (Mesh *)id);
+ break;
+ case ID_PA:
+ write_particlesettings(wd, (ParticleSettings *)id);
+ break;
+ case ID_NT:
+ write_nodetree(wd, (bNodeTree *)id);
+ break;
+ case ID_BR:
+ write_brush(wd, (Brush *)id);
+ break;
+ case ID_PAL:
+ write_palette(wd, (Palette *)id);
+ break;
+ case ID_PC:
+ write_paintcurve(wd, (PaintCurve *)id);
+ break;
+ case ID_GD:
+ write_gpencil(wd, (bGPdata *)id);
+ break;
+ case ID_LS:
+ write_linestyle(wd, (FreestyleLineStyle *)id);
+ break;
+ case ID_CF:
+ write_cachefile(wd, (CacheFile *)id);
+ break;
+ case ID_LI:
+ /* Do nothing, handled below - and should never be reached. */
+ BLI_assert(0);
+ break;
+ case ID_IP:
+ /* Do nothing, deprecated. */
+ break;
+ default:
+ /* Should never be reached. */
+ BLI_assert(0);
+ break;
+ }
+
+ if (do_override) {
+ BKE_override_static_operations_store_end(override_storage, id);
+ }
}
+
+ mywrite_flush(wd);
}
+ } while ((bmain != override_storage) && (bmain = override_storage));
- mywrite_flush(wd);
+ if (override_storage) {
+ BKE_override_static_operations_store_finalize(override_storage);
+ override_storage = NULL;
}
/* Special handling, operating over split Mains... */
diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c
index 432c82afe4a..1b96237e262 100644
--- a/source/blender/bmesh/intern/bmesh_marking.c
+++ b/source/blender/bmesh/intern/bmesh_marking.c
@@ -254,8 +254,8 @@ void BM_mesh_select_mode_flush_ex(BMesh *bm, const short selectmode)
/* both loops only set edge/face flags and read off verts */
BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
if (BM_elem_flag_test(e->v1, BM_ELEM_SELECT) &&
- BM_elem_flag_test(e->v2, BM_ELEM_SELECT) &&
- !BM_elem_flag_test(e, BM_ELEM_HIDDEN))
+ BM_elem_flag_test(e->v2, BM_ELEM_SELECT) &&
+ !BM_elem_flag_test(e, BM_ELEM_HIDDEN))
{
BM_elem_flag_enable(e, BM_ELEM_SELECT);
}
@@ -366,8 +366,8 @@ void BM_mesh_select_flush(BMesh *bm)
BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
if (BM_elem_flag_test(e->v1, BM_ELEM_SELECT) &&
- BM_elem_flag_test(e->v2, BM_ELEM_SELECT) &&
- !BM_elem_flag_test(e, BM_ELEM_HIDDEN))
+ BM_elem_flag_test(e->v2, BM_ELEM_SELECT) &&
+ !BM_elem_flag_test(e, BM_ELEM_HIDDEN))
{
BM_elem_flag_enable(e, BM_ELEM_SELECT);
}
diff --git a/source/blender/bmesh/operators/bmo_rotate_edges.c b/source/blender/bmesh/operators/bmo_rotate_edges.c
index dd6bf77dd3c..9832fdb57d3 100644
--- a/source/blender/bmesh/operators/bmo_rotate_edges.c
+++ b/source/blender/bmesh/operators/bmo_rotate_edges.c
@@ -18,7 +18,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/bmesh/operators/bmo_rotate_edge.c
+/** \file blender/bmesh/operators/bmo_rotate_edges.c
* \ingroup bmesh
*
* Rotate edges topology that share two faces.
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index 51a0fa4b2cc..2c6213dacce 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -117,7 +117,7 @@ typedef struct Profile {
float *prof_co; /* seg+1 profile coordinates (triples of floats) */
float *prof_co_2; /* like prof_co, but for seg power of 2 >= seg */
} Profile;
-#define PRO_SQUARE_R 4.0f
+#define PRO_SQUARE_R 1e4f
#define PRO_CIRCLE_R 2.0f
#define PRO_LINE_R 1.0f
#define PRO_SQUARE_IN_R 0.0f
@@ -126,8 +126,10 @@ typedef struct Profile {
* get even spacing on superellipse for current BevelParams seg
* and pro_super_r. */
typedef struct ProfileSpacing {
- float *uvals; /* seg+1 u values */
- float *uvals_2; /* seg_2+1 u values, seg_2 = power of 2 >= seg */
+ double *xvals; /* seg+1 x values */
+ double *xvals_2; /* seg_2+1 x values, seg_2 = power of 2 >= seg */
+ double *yvals; /* seg+1 y values */
+ double *yvals_2; /* seg_2+1 y values, seg_2 = power of 2 >= seg */
int seg_2; /* the seg_2 value */
} ProfileSpacing;
@@ -1383,56 +1385,21 @@ static void make_unit_cube_map(
r_mat[3][3] = 1.0f;
}
-/* Get the coordinate on the superellipse (exponent r),
- * at parameter value u. u goes from u to 2 as the
- * superellipse moves on the quadrant (0,1) to (1,0). */
-static void superellipse_co(float u, float r, float r_co[2])
+/* Get the coordinate on the superellipse (x^r + y^r = 1),
+ * at parameter value x (or, if !rbig, mirrored (y=x)-line).
+ * rbig should be true if r > 1.0 and false if <= 1.0.
+ * Assume r > 0.0 */
+static double superellipse_co(double x, float r, bool rbig)
{
- float t;
-
- if (u <= 0.0f) {
- r_co[0] = 0.0f;
- r_co[1] = 1.0f;
- }
- else if (u >= 2.0f) {
- r_co[0] = 1.0f;
- r_co[1] = 0.0f;
- }
- else if (r == PRO_LINE_R) {
- t = u / 2.0f;
- r_co[0] = t;
- r_co[1] = 1.0f - t;
-
- }
- else if (r == PRO_SQUARE_IN_R) {
- if (u < 1.0f) {
- r_co[0] = 0.0f;
- r_co[1] = 1.0f - u;
- }
- else {
- r_co[0] = u - 1.0f;
- r_co[1] = 0.0f;
- }
- }
- else if (r == PRO_SQUARE_R) {
- if (u < 1.0f) {
- r_co[0] = u;
- r_co[1] = 1.0f;
- }
- else {
- r_co[0] = 1.0f;
- r_co[1] = 2.0f - u;
- }
-
+ BLI_assert(r > 0.0f);
+
+ /* If r<1, mirror the superellipse function by (y=x)-line to get a numerically stable range
+ * Possible because of symmetry, later mirror back. */
+ if (rbig) {
+ return pow((1.0 - pow(x, r)), (1.0 / r));
}
else {
- t = u * (float)M_PI / 4.0f; /* angle from y axis */
- r_co[0] = sinf(t);
- r_co[1] = cosf(t);
- if (r != PRO_SQUARE_R) {
- r_co[0] = pow(r_co[0], 2.0f / r);
- r_co[1] = pow(r_co[1], 2.0f / r);
- }
+ return 1.0 - pow((1.0 - pow(1.0 - x, r)), (1.0 / r));
}
}
@@ -1478,7 +1445,7 @@ static void get_profile_point(BevelParams *bp, const Profile *pro, int i, int n,
static void calculate_profile(BevelParams *bp, BoundVert *bndv)
{
int i, k, ns;
- const float *uvals;
+ const double *xvals, *yvals;
float co[3], co2[3], p[3], m[4][4];
float *prof_co, *prof_co_k;
float r;
@@ -1504,17 +1471,19 @@ static void calculate_profile(BevelParams *bp, BoundVert *bndv)
for (i = 0; i < 2; i++) {
if (i == 0) {
ns = bp->seg;
- uvals = bp->pro_spacing.uvals;
+ xvals = bp->pro_spacing.xvals;
+ yvals = bp->pro_spacing.yvals;
prof_co = pro->prof_co;
}
else {
if (!need_2)
break; /* shares coords with pro->prof_co */
ns = bp->pro_spacing.seg_2;
- uvals = bp->pro_spacing.uvals_2;
+ xvals = bp->pro_spacing.xvals_2;
+ yvals = bp->pro_spacing.yvals_2;
prof_co = pro->prof_co_2;
}
- BLI_assert((r == PRO_LINE_R || uvals != NULL) && prof_co != NULL);
+ BLI_assert((r == PRO_LINE_R || (xvals != NULL && yvals != NULL)) && prof_co != NULL);
for (k = 0; k <= ns; k++) {
if (k == 0)
copy_v3_v3(co, pro->coa);
@@ -1522,7 +1491,8 @@ static void calculate_profile(BevelParams *bp, BoundVert *bndv)
copy_v3_v3(co, pro->cob);
else {
if (map_ok) {
- superellipse_co(uvals[k], r, p);
+ p[0] = xvals[k];
+ p[1] = yvals[k];
p[2] = 0.0f;
mul_v3_m4v3(co, m, p);
}
@@ -2581,9 +2551,8 @@ static VMesh *cubic_subdiv(BevelParams *bp, VMesh *vm0)
return vm1;
}
-/* Special case for cube corner, when r is PRO_SQUARE_R,
- * meaning straight sides */
-static VMesh *make_cube_corner_straight(MemArena *mem_arena, int nseg)
+/* Special case for cube corner, when r is PRO_SQUARE_R, meaning straight sides */
+static VMesh *make_cube_corner_square(MemArena *mem_arena, int nseg)
{
VMesh *vm;
float co[3];
@@ -2613,6 +2582,46 @@ static VMesh *make_cube_corner_straight(MemArena *mem_arena, int nseg)
return vm;
}
+/* Special case for cube corner, when r is PRO_SQUARE_IN_R, meaning inward
+ * straight sides.
+ * We mostly don't want a VMesh at all for this case -- just a three-way weld
+ * with a triangle in the middle for odd nseg */
+static VMesh *make_cube_corner_square_in(MemArena *mem_arena, int nseg)
+{
+ VMesh *vm;
+ float co[3];
+ float b;
+ int i, k, ns2, odd;
+
+ ns2 = nseg / 2;
+ odd = nseg % 2;
+ vm = new_adj_vmesh(mem_arena, 3, nseg, NULL);
+ vm->count = 0; // reset, so following loop will end up with correct count
+ for (i = 0; i < 3; i++) {
+ zero_v3(co);
+ co[i] = 1.0f;
+ add_new_bound_vert(mem_arena, vm, co);
+ }
+ if (odd)
+ b = 2.0f / (2.0f * (float)ns2 + (float)M_SQRT2);
+ else
+ b = 2.0f / (float)nseg;
+ for (i = 0; i < 3; i++) {
+ for (k = 0; k <= ns2; k++) {
+ co[i] = 1.0f - (float)k * b;
+ co[(i + 1) % 3] = 0.0f;
+ co[(i + 2) % 3] = 0.0f;
+ copy_v3_v3(mesh_vert(vm, i, 0, k)->co, co);
+ co[(i + 1) % 3] = 1.0f - (float)k * b;
+ co[(i + 2) % 3] = 0.0f;
+ co[i] = 0.0f;
+ copy_v3_v3(mesh_vert(vm, i, 0, nseg - k)->co, co);
+ }
+ }
+ return vm;
+}
+
+
/* Make a VMesh with nseg segments that covers the unit radius sphere octant
* with center at (0,0,0).
* This has BoundVerts at (1,0,0), (0,1,0) and (0,0,1), with quarter circle arcs
@@ -2629,7 +2638,9 @@ static VMesh *make_cube_corner_adj_vmesh(BevelParams *bp)
float co[3], coc[3];
if (r == PRO_SQUARE_R)
- return make_cube_corner_straight(mem_arena, nseg);
+ return make_cube_corner_square(mem_arena, nseg);
+ else if (r == PRO_SQUARE_IN_R)
+ return make_cube_corner_square_in(mem_arena, nseg);
/* initial mesh has 3 sides, 2 segments */
vm0 = new_adj_vmesh(mem_arena, 3, 2, NULL);
@@ -2687,6 +2698,7 @@ static VMesh *make_cube_corner_adj_vmesh(BevelParams *bp)
}
}
}
+
return vm1;
}
@@ -2944,6 +2956,87 @@ static float snap_face_dist_squared(float *co, BMFace *f, BMEdge **r_snap_e, flo
return beste_d2;
}
+static void build_center_ngon(BMesh *bm, BevVert *bv, int mat_nr)
+{
+ VMesh *vm = bv->vmesh;
+ BoundVert *v;
+ int i, ns2;
+ BMFace *frep;
+ BMEdge *frep_e1, *frep_e2, *frep_e;
+ BMVert **vv = NULL;
+ BMFace **vf = NULL;
+ BMEdge **ve = NULL;
+ BLI_array_staticdeclare(vv, BM_DEFAULT_NGON_STACK_SIZE);
+ BLI_array_staticdeclare(vf, BM_DEFAULT_NGON_STACK_SIZE);
+ BLI_array_staticdeclare(ve, BM_DEFAULT_NGON_STACK_SIZE);
+
+ ns2 = vm->seg / 2;
+ if (bv->any_seam) {
+ frep = boundvert_rep_face(vm->boundstart, NULL);
+ get_incident_edges(frep, bv->v, &frep_e1, &frep_e2);
+ }
+ else {
+ frep = NULL;
+ frep_e1 = frep_e2 = NULL;
+ }
+ v = vm->boundstart;
+ do {
+ i = v->index;
+ BLI_array_append(vv, mesh_vert(vm, i, ns2, ns2)->v);
+ if (frep) {
+ BLI_array_append(vf, frep);
+ frep_e = find_closer_edge(mesh_vert(vm, i, ns2, ns2)->v->co, frep_e1, frep_e2);
+ BLI_array_append(ve, v == vm->boundstart ? NULL : frep_e);
+ }
+ else {
+ BLI_array_append(vf, boundvert_rep_face(v, NULL));
+ BLI_array_append(ve, NULL);
+ }
+ } while ((v = v->next) != vm->boundstart);
+ bev_create_ngon(bm, vv, BLI_array_count(vv), vf, frep, ve, mat_nr, true);
+
+ BLI_array_free(vv);
+ BLI_array_free(vf);
+ BLI_array_free(ve);
+}
+
+/* Special case of bevel_build_rings when tri-corner and profile is 0.
+ * There is no corner mesh except, if nseg odd, for a center poly.
+ * Boundary verts merge with previous ones according to pattern:
+ * (i, 0, k) merged with (i+1, 0, ns-k) for k <= ns/2 */
+static void build_square_in_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv, VMesh *vm1)
+{
+ int n, ns, ns2, odd, i, k;
+ VMesh *vm;
+
+ vm = bv->vmesh;
+ n = vm->count;
+ ns = vm->seg;
+ ns2 = ns / 2;
+ odd = ns % 2;
+
+ for (i = 0; i < n; i++) {
+ for (k = 1; k < ns; k++) {
+ copy_v3_v3(mesh_vert(vm, i, 0, k)->co, mesh_vert(vm1, i, 0, k)->co);
+ if (i > 0 && k <= ns2) {
+ mesh_vert(vm, i, 0, k)->v = mesh_vert(vm, i - 1, 0, ns - k)->v;
+ }
+ else if (i == n - 1 && k > ns2) {
+ mesh_vert(vm, i, 0, k)->v = mesh_vert(vm, 0, 0, ns - k)->v;
+ }
+ else {
+ create_mesh_bmvert(bm, vm, i, 0, k, bv->v);
+ }
+ }
+ }
+ if (odd) {
+ for (i = 0; i < n; i++) {
+ mesh_vert(vm, i, ns2, ns2)->v = mesh_vert(vm, i, 0, ns2)->v;
+ }
+ build_center_ngon(bm, bv, bp->mat_nr);
+ }
+}
+
/*
* Given that the boundary is built and the boundary BMVerts have been made,
* calculate the positions of the interior mesh points for the M_ADJ pattern,
@@ -2968,12 +3061,21 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv)
vpipe = pipe_test(bv);
- if (vpipe)
+ if (vpipe) {
vm1 = pipe_adj_vmesh(bp, bv, vpipe);
- else if (tri_corner_test(bp, bv))
+ }
+ else if (tri_corner_test(bp, bv)) {
vm1 = tri_corner_adj_vmesh(bp, bv);
- else
+ /* the PRO_SQUARE_IN_R profile has boundary edges that merge
+ * and no internal ring polys except possibly center ngon */
+ if (bp->pro_super_r == PRO_SQUARE_IN_R) {
+ build_square_in_vmesh(bp, bm, bv, vm1);
+ return;
+ }
+ }
+ else {
vm1 = adj_vmesh(bp, bv);
+ }
/* copy final vmesh into bv->vmesh, make BMVerts and BMFaces */
vm = bv->vmesh;
@@ -3086,42 +3188,7 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv)
/* center ngon */
if (odd) {
- BMFace *frep;
- BMEdge *frep_e1, *frep_e2, *frep_e;
- BMVert **vv = NULL;
- BMFace **vf = NULL;
- BMEdge **ve = NULL;
- BLI_array_staticdeclare(vv, BM_DEFAULT_NGON_STACK_SIZE);
- BLI_array_staticdeclare(vf, BM_DEFAULT_NGON_STACK_SIZE);
- BLI_array_staticdeclare(ve, BM_DEFAULT_NGON_STACK_SIZE);
-
- if (bv->any_seam) {
- frep = boundvert_rep_face(vm->boundstart, NULL);
- get_incident_edges(frep, bv->v, &frep_e1, &frep_e2);
- }
- else {
- frep = NULL;
- frep_e1 = frep_e2 = NULL;
- }
- v = vm->boundstart;
- do {
- i = v->index;
- BLI_array_append(vv, mesh_vert(vm, i, ns2, ns2)->v);
- if (frep) {
- BLI_array_append(vf, frep);
- frep_e = find_closer_edge(mesh_vert(vm, i, ns2, ns2)->v->co, frep_e1, frep_e2);
- BLI_array_append(ve, v == vm->boundstart ? NULL : frep_e);
- }
- else {
- BLI_array_append(vf, boundvert_rep_face(v, NULL));
- BLI_array_append(ve, NULL);
- }
- } while ((v = v->next) != vm->boundstart);
- bev_create_ngon(bm, vv, BLI_array_count(vv), vf, frep, ve, mat_nr, true);
-
- BLI_array_free(vv);
- BLI_array_free(vf);
- BLI_array_free(ve);
+ build_center_ngon(bm, bv, mat_nr);
}
}
@@ -4389,143 +4456,296 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme)
}
}
-/* Returns the square of the length of the chord from parameter u0 to parameter u1
- * of superellipse_co. */
-static float superellipse_chord_length_squared(float u0, float u1, float r)
-{
- float a[2], b[2];
- BLI_assert(u0 >= 0.0f && u1 >= u0 && u1 <= 2.0f);
- superellipse_co(u0, r, a);
- superellipse_co(u1, r, b);
- return len_squared_v2v2(a, b);
+/* Find xnew > x0 so that distance((x0,y0), (xnew, ynew)) = dtarget.
+ * False position Illinois method used because the function is somewhat linear
+ * -> linear interpolation converges fast.
+ * Assumes that the gradient is always between 1 and -1 for
+ * x in [x0, x0+dtarget] */
+static double find_superellipse_chord_endpoint(double x0, double dtarget, float r, bool rbig)
+{
+ double xmin, xmax, ymin, ymax, dmaxerr, dminerr, dnewerr, xnew, ynew;
+ double y0 = superellipse_co(x0, r, rbig);
+ const double tol = 1e-13; // accumulates for many segments so use low value
+ const int maxiter = 10;
+ bool lastupdated_upper;
+
+ /* For gradient between -1 and 1, xnew can only be in
+ * [x0 + sqrt(2)/2*dtarget, x0 + dtarget]. */
+ xmin = x0 + M_SQRT2 / 2.0 * dtarget;
+ if (xmin > 1.0)
+ xmin = 1.0;
+ xmax = x0 + dtarget;
+ if (xmax > 1.0)
+ xmax = 1.0;
+ ymin = superellipse_co(xmin, r, rbig);
+ ymax = superellipse_co(xmax, r, rbig);
+
+ /* Note: using distance**2 (no sqrt needed) does not converge that well. */
+ dmaxerr = sqrt(pow((xmax - x0), 2) + pow((ymax - y0), 2)) - dtarget;
+ dminerr = sqrt(pow((xmin - x0), 2) + pow((ymin - y0), 2)) - dtarget;
+
+ xnew = xmax - dmaxerr * (xmax - xmin) / (dmaxerr - dminerr);
+ lastupdated_upper = true;
+
+ for (int iter = 0; iter < maxiter; iter++) {
+ ynew = superellipse_co(xnew, r, rbig);
+ dnewerr = sqrt(pow((xnew - x0), 2) + pow((ynew - y0), 2)) - dtarget;
+ if (fabs(dnewerr) < tol) {
+ break;
+ }
+ if (dnewerr < 0) {
+ xmin = xnew;
+ ymin = ynew;
+ dminerr = dnewerr;
+ if (!lastupdated_upper) {
+ xnew = (dmaxerr / 2 * xmin - dminerr * xmax) / (dmaxerr / 2 - dminerr);
+ }
+ else {
+ xnew = xmax - dmaxerr * (xmax - xmin) / (dmaxerr - dminerr);
+ }
+ lastupdated_upper = false;
+ }
+ else {
+ xmax = xnew;
+ ymax = ynew;
+ dmaxerr = dnewerr;
+ if (lastupdated_upper) {
+ xnew = (dmaxerr * xmin - dminerr / 2 * xmax) / (dmaxerr - dminerr / 2);
+ }
+ else {
+ xnew = xmax - dmaxerr * (xmax - xmin) / (dmaxerr - dminerr);
+ }
+ lastupdated_upper = true;
+ }
+ }
+ return xnew;
}
-/* Find parameter u >= u0 to make chord of squared length d2goal,
- * from u0 to u on superellipse with parameter r.
- * If it cannot be found, return -1.0f. */
-static float find_superellipse_chord_u(float u0, float d2goal, float r)
+ /* This search procedure to find equidistant points (x,y) in the first
+ * superellipse quadrant works for every superellipse exponent but is more
+ * expensive than known solutions for special cases.
+ * Call the point on superellipse that intersects x=y line mx.
+ * For r>=1 use only the range x in [0,mx] and mirror the rest along x=y line,
+ * for r<1 use only x in [mx,1]. Points are initially spaced and iteratively
+ * repositioned to have the same distance. */
+
+static void find_even_superellipse_chords_general(int seg, float r, double *xvals, double *yvals)
{
- float ulow, uhigh, u, d2, d2max;
- const float dtol = 1e-4f;
- const float utol = 1e-6f;
- const float umax = 2.0f;
-
- if (d2goal == 0.0f)
- return u0;
- d2max = superellipse_chord_length_squared(u0, umax, r);
- if (fabsf(d2goal - d2max) <= dtol)
- return umax;
- if (d2goal - d2max > dtol)
- return -1.0f;
-
- /* binary search for good u value */
- ulow = u0;
- uhigh = umax;
- do {
- u = 0.5f * (ulow + uhigh);
- d2 = superellipse_chord_length_squared(u0, u, r);
- if (fabsf(d2goal - d2) <= dtol)
+ const int smoothitermax = 10;
+ const double error_tol = 1e-7;
+ int i;
+ int imax = (seg + 1) / 2 - 1; /* ceiling division - 1 */
+
+ double d, dmin, dmax;
+ double davg;
+ double mx;
+ double sum;
+ double temp;
+
+ bool precision_reached;
+ bool seg_odd = seg % 2;
+ bool rbig;
+
+ if (r > 1.0f) {
+ rbig = true;
+ mx = pow(0.5, 1.0 / r);
+ }
+ else {
+ rbig = false;
+ mx = 1 - pow(0.5, 1.0 / r);
+ }
+
+ /* Initial positions, linear spacing along x axis. */
+ for (i = 0; i <= imax; i++) {
+ xvals[i] = i * mx / seg * 2;
+ yvals[i] = superellipse_co(xvals[i], r, rbig);
+ }
+ yvals[0] = 1;
+
+ /* Smooth distance loop */
+ for (int iter = 0; iter < smoothitermax; iter++) {
+ sum = 0.0;
+ dmin = 2.0;
+ dmax = 0.0;
+ /* Update distances between neighbor points. Store the highest and
+ * lowest to see if the maximum error to average distance (which isn't
+ * known yet) is below required precision. */
+ for (i = 0; i < imax; i++) {
+ d = sqrt(pow((xvals[i + 1] - xvals[i]), 2) + pow((yvals[i + 1] - yvals[i]), 2));
+ sum += d;
+ if (d > dmax) {
+ dmax = d;
+ }
+ if (d < dmin) {
+ dmin = d;
+ }
+ }
+ /* For last distance, weight with 1/2 if seg_odd. */
+ if (seg_odd) {
+ sum += M_SQRT2 / 2 * (yvals[imax] - xvals[imax]);
+ davg = sum / (imax + 0.5);
+ }
+ else {
+ sum += sqrt(pow((xvals[imax] - mx), 2) + pow((yvals[imax] - mx), 2));
+ davg = sum / (imax + 1.0);
+ }
+ /* Max error in tolerance? -> Quit. */
+ if (dmax - davg > error_tol) {
+ precision_reached = false;
+ }
+ if (dmin - davg < error_tol) {
+ precision_reached = false;
+ }
+ if (precision_reached) {
break;
- if (d2 < d2goal)
- ulow = u;
- else
- uhigh = u;
- } while (fabsf(uhigh - ulow) > utol);
- return u;
+ }
+
+
+ /* Update new coordinates. */
+ for (i = 1; i <= imax; i++) {
+ xvals[i] = find_superellipse_chord_endpoint(xvals[i - 1], davg, r, rbig);
+ yvals[i] = superellipse_co(xvals[i], r, rbig);
+ }
+ }
+
+ /* Fill remaining. */
+ if (!seg_odd) {
+ xvals[imax + 1] = mx;
+ yvals[imax + 1] = mx;
+ }
+ for (i = imax + 1; i <= seg; i++) {
+ yvals[i] = xvals[seg - i];
+ xvals[i] = yvals[seg - i];
+ }
+
+ if (!rbig) {
+ for (i = 0; i <= seg; i++) {
+ temp = xvals[i];
+ xvals[i] = 1.0 - yvals[i];
+ yvals[i] = 1.0 - temp;
+ }
+ }
}
-/* Find parameters u0, u1, ..., un that divide the quarter-arc superellipse
- * with parameter r into n even chords.
- * There is no closed form way of doing this except for a few special
- * values of r, so this uses binary search to find a chord length that works.
- * Return the u's in *r_params, which should point to an array of size n+1. */
-static void find_even_superellipse_params(int n, float r, float *r_params)
+ /* Find equidistant points (x0,y0), (x1,y1)... (xn,yn) on the superellipse
+ * function in the first quadrant. For special profiles (linear, arc,
+ * rectangle) the point can be calculated easily, for any other profile a more
+ * expensive search procedure must be used because there is no known closed
+ * form for equidistant parametrization
+ * xvals and yvals should be size n+1 */
+
+static void find_even_superellipse_chords(int n, float r, double *xvals, double *yvals)
{
- float d2low, d2high, d2 = 0.0f, d2final, u;
- int i, j, n2;
- const int maxiters = 40;
- const float d2tol = 1e-6f;
- const float umax = 2.0f;
-
- if (r == PRO_CIRCLE_R || r == PRO_LINE_R ||
- ((n % 2 == 0) && (r == PRO_SQUARE_IN_R || r == PRO_SQUARE_R)))
- {
- /* even parameter spacing works for these cases */
- for (i = 0; i <= n; i++)
- r_params[i] = i * 2.0f / (float) n;
+ int i, n2;
+ double temp;
+ bool seg_odd = n % 2;
+
+ n2 = n / 2;
+
+ /* Special cases. */
+ if (r == PRO_LINE_R) {
+ /* Linear spacing */
+ for (i = 0; i <= n; i++) {
+ xvals[i] = (double) i / n;
+ yvals[i] = 1.0 - (double) i / n;
+ }
return;
}
- if (r == PRO_SQUARE_IN_R || r == PRO_SQUARE_R) {
- /* n is odd, so get one corner-cut chord.
- * Solve u == sqrt(2*(1-n2*u)^2) where n2 = floor(n/2) */
- n2 = n / 2;
- u = (2.0f * n2 - (float)M_SQRT2) / (2.0f * n2 * n2 - 1.0f);
- for (i = 0; i < n; i++)
- r_params[i] = i * u;
- r_params[n] = umax;
- }
- d2low = 2.0f / (n * n); /* (sqrt(2)/n)**2 */
- d2high = 2 * d2low; /* (2/n)**2 */
- for (i = 0; i < maxiters && fabsf(d2high - d2low) > d2tol; i++) {
- d2 = 0.5f * (d2low + d2high);
-
- /* find where we are after n-1 chords of squared length d2 */
- u = 0.0f;
- for (j = 0; j < n - 1; j++) {
- u = find_superellipse_chord_u(u, d2, r);
- if (u == -1.0f)
- break; /* d2 is too big to go n-1 chords */
- }
- if (u == -1.0f) {
- d2high = d2;
- continue;
+ if (r == PRO_CIRCLE_R) {
+ temp = (M_PI / 2) / n;
+ /* Angle spacing. */
+ for (i = 0; i <= n; i++) {
+ xvals[i] = sin(i * temp);
+ yvals[i] = cos(i * temp);
}
- d2final = superellipse_chord_length_squared(u, umax, r);
- if (fabsf(d2final - d2) <= d2tol)
- break;
- if (d2final < d2)
- d2high = d2;
- else
- d2low = d2;
+ return;
}
- u = 0.0f;
- for (i = 0; i < n; i++) {
- r_params[i] = u;
- u = find_superellipse_chord_u(u, d2, r);
+ if (r == PRO_SQUARE_IN_R) {
+ /* n is even, distribute first and second half linear. */
+ if (!seg_odd) {
+ for (i = 0; i <= n2; i++) {
+ xvals[i] = 0.0;
+ yvals[i] = 1.0 - (double) i / n2;
+ xvals[n - i] = yvals[i];
+ yvals[n - i] = xvals[i];
+ }
+ }
+ /* n is odd, so get one corner-cut chord. */
+ else {
+ temp = 1.0 / (n2 + M_SQRT2 / 2.0);
+ for (i = 0; i <= n2; i++) {
+ xvals[i] = 0.0;
+ yvals[i] = 1.0 - (double) i * temp;
+ xvals[n -i ] = yvals[i];
+ yvals[n - i] = xvals[i];
+ }
+ }
+ return;
}
- r_params[n] = umax;
+ if (r == PRO_SQUARE_R) {
+ /* n is even, distribute first and second half linear. */
+ if (!seg_odd) {
+ for (i = 0; i <= n2; i++) {
+ xvals[i] = (double) i / n2;
+ yvals[i] = 1.0;
+ xvals[n - i] = yvals[i];
+ yvals[n - i] = xvals[i];
+ }
+ }
+ /* n is odd, so get one corner-cut chord. */
+ else {
+ temp = 1.0 / (n2 + M_SQRT2 / 2);
+ for (i = 0; i <= n2; i++) {
+ xvals[i] = (double) i * temp;
+ yvals[i] = 1.0;
+ xvals[n - i] = yvals[i];
+ yvals[n - i] = xvals[i];
+ }
+ }
+ return;
+ }
+ /* For general case use the more expensive search algorithm. */
+ find_even_superellipse_chords_general(n, r, xvals, yvals);
}
+
/* The superellipse used for multisegment profiles does not
* have a closed-form way to generate evenly spaced points
* along an arc. We use an expensive search procedure to find
* the parameter values that lead to bp->seg even chords.
* We also want spacing for a number of segments that is
- * a power of 2 >= bp->seg (but at least 4). */
+ * a power of 2 >= bp->seg (but at least 4).
+ * Use doubles because otherwise we cannot come close to float
+ * precision for final results. */
static void set_profile_spacing(BevelParams *bp)
{
int seg, seg_2;
seg = bp->seg;
if (seg > 1) {
- bp->pro_spacing.uvals = (float *)BLI_memarena_alloc(bp->mem_arena, (seg + 1) * sizeof(float));
- find_even_superellipse_params(seg, bp->pro_super_r, bp->pro_spacing.uvals);
+ bp->pro_spacing.xvals = (double *)BLI_memarena_alloc(bp->mem_arena, (seg + 1) * sizeof(double));
+ bp->pro_spacing.yvals = (double *)BLI_memarena_alloc(bp->mem_arena, (seg + 1) * sizeof(double));
+ find_even_superellipse_chords(seg, bp->pro_super_r, bp->pro_spacing.xvals, bp->pro_spacing.yvals);
seg_2 = power_of_2_max_i(bp->seg);
if (seg_2 == 2)
seg_2 = 4;
bp->pro_spacing.seg_2 = seg_2;
if (seg_2 == seg) {
- bp->pro_spacing.uvals_2 = bp->pro_spacing.uvals;
+ bp->pro_spacing.xvals_2 = bp->pro_spacing.xvals;
+ bp->pro_spacing.yvals_2 = bp->pro_spacing.yvals;
}
else {
- bp->pro_spacing.uvals_2 = (float *)BLI_memarena_alloc(bp->mem_arena, (seg_2 + 1) * sizeof(float));
- find_even_superellipse_params(seg_2, bp->pro_super_r, bp->pro_spacing.uvals_2);
+ bp->pro_spacing.xvals_2 = (double *)BLI_memarena_alloc(bp->mem_arena, (seg_2 + 1) * sizeof(double));
+ bp->pro_spacing.yvals_2 = (double *)BLI_memarena_alloc(bp->mem_arena, (seg_2 + 1) * sizeof(double));
+ find_even_superellipse_chords(seg_2, bp->pro_super_r, bp->pro_spacing.xvals_2, bp->pro_spacing.yvals_2);
}
}
else {
- bp->pro_spacing.uvals = NULL;
- bp->pro_spacing.uvals_2 = NULL;
+ bp->pro_spacing.xvals = NULL;
+ bp->pro_spacing.yvals = NULL;
+ bp->pro_spacing.xvals_2 = NULL;
+ bp->pro_spacing.yvals_2 = NULL;
bp->pro_spacing.seg_2 = 0;
}
}
@@ -4754,7 +4974,7 @@ void BM_mesh_bevel(
bp.offset = offset;
bp.offset_type = offset_type;
bp.seg = segments;
- bp.pro_super_r = 4.0f * profile; /* convert to superellipse exponent */
+ bp.pro_super_r = -log(2.0) / log(sqrt(profile)); /* convert to superellipse exponent */
bp.vertex_only = vertex_only;
bp.use_weights = use_weights;
bp.loop_slide = loop_slide;
@@ -4763,8 +4983,9 @@ void BM_mesh_bevel(
bp.vertex_group = vertex_group;
bp.mat_nr = mat;
- if (bp.pro_super_r < 0.60f)
- bp.pro_super_r = 0.60f; /* TODO: implement 0 case properly */
+ if (profile >= 0.999f) { /* r ~ 692, so PRO_SQUARE_R is 1e4 */
+ bp.pro_super_r = PRO_SQUARE_R;
+ }
if (bp.offset > 0) {
/* primary alloc */
diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp
index 8908d0e603f..d3e23f740c8 100644
--- a/source/blender/collada/DocumentImporter.cpp
+++ b/source/blender/collada/DocumentImporter.cpp
@@ -267,7 +267,7 @@ void DocumentImporter::finish()
std::vector<Object *>::iterator it;
for (it = libnode_ob.begin(); it != libnode_ob.end(); it++) {
Object *ob = *it;
- BKE_collections_object_remove(G.main, sce, ob, true);
+ BKE_collections_object_remove(G.main, &sce->id, ob, true);
}
libnode_ob.clear();
diff --git a/source/blender/collada/SceneExporter.cpp b/source/blender/collada/SceneExporter.cpp
index aa98f2ee96c..c375c09d869 100644
--- a/source/blender/collada/SceneExporter.cpp
+++ b/source/blender/collada/SceneExporter.cpp
@@ -26,6 +26,7 @@
extern "C" {
#include "BLI_utildefines.h"
+ #include "BKE_group.h"
#include "BKE_object.h"
#include "BLI_listbase.h"
}
@@ -177,12 +178,13 @@ void SceneExporter::writeNodes(const EvaluationContext *eval_ctx, Object *ob, Sc
// empty object
else if (ob->type == OB_EMPTY) { // TODO: handle groups (OB_DUPLIGROUP
if ((ob->transflag & OB_DUPLIGROUP) == OB_DUPLIGROUP && ob->dup_group) {
- GroupObject *go = NULL;
- Group *gr = ob->dup_group;
- /* printf("group detected '%s'\n", gr->id.name + 2); */
- for (go = (GroupObject *)(gr->gobject.first); go; go = go->next) {
- printf("\t%s\n", go->ob->id.name);
+ Group *group = ob->dup_group;
+ /* printf("group detected '%s'\n", group->id.name + 2); */
+ FOREACH_GROUP_OBJECT(group, object)
+ {
+ printf("\t%s\n", object->id.name);
}
+ FOREACH_GROUP_OBJECT_END
}
}
diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp
index 1a6f2675cc7..6a52027fb47 100644
--- a/source/blender/collada/collada_utils.cpp
+++ b/source/blender/collada/collada_utils.cpp
@@ -147,7 +147,7 @@ Object *bc_add_object(Scene *scene, int type, const char *name)
ViewLayer *view_layer = BKE_view_layer_context_active_PLACEHOLDER(scene);
LayerCollection *layer_collection = BKE_layer_collection_get_active_ensure(scene, view_layer);
- BKE_collection_object_add(scene, layer_collection->scene_collection, ob);
+ BKE_collection_object_add(&scene->id, layer_collection->scene_collection, ob);
Base *base = BKE_view_layer_base_find(view_layer, ob);
BKE_view_layer_base_select(view_layer, base);
diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt
index 8b1ce5a9926..9495321a0ff 100644
--- a/source/blender/depsgraph/CMakeLists.txt
+++ b/source/blender/depsgraph/CMakeLists.txt
@@ -65,6 +65,8 @@ set(SRC
intern/depsgraph_debug.cc
intern/depsgraph_eval.cc
intern/depsgraph_query.cc
+ intern/depsgraph_query_foreach.cc
+ intern/depsgraph_query_iter.cc
intern/depsgraph_tag.cc
intern/depsgraph_type_defines.cc
@@ -78,6 +80,7 @@ set(SRC
intern/builder/deg_builder_nodes.h
intern/builder/deg_builder_pchanmap.h
intern/builder/deg_builder_relations.h
+ intern/builder/deg_builder_relations_impl.h
intern/builder/deg_builder_transitive.h
intern/eval/deg_eval.h
intern/eval/deg_eval_copy_on_write.h
diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h
index 7b1f1fc8ca9..6bcbff4950b 100644
--- a/source/blender/depsgraph/DEG_depsgraph.h
+++ b/source/blender/depsgraph/DEG_depsgraph.h
@@ -86,7 +86,7 @@ typedef struct EvaluationContext {
struct Depsgraph *depsgraph;
struct ViewLayer *view_layer;
- struct RenderEngineType *engine;
+ struct RenderEngineType *engine_type;
} EvaluationContext;
/* DagNode->eval_flags */
@@ -151,9 +151,9 @@ enum {
DEG_TAG_TIME = (1 << 2),
/* Particle system changed. */
- DEG_TAG_PSYSC_REDO = (1 << 3),
- DEG_TAG_PSYS_RESET = (1 << 4),
- DEG_TAG_PSYS_TYPE = (1 << 5),
+ DEG_TAG_PSYSC_REDO = (1 << 3),
+ DEG_TAG_PSYS_RESET = (1 << 4),
+ DEG_TAG_PSYS_TYPE = (1 << 5),
DEG_TAG_PSYS_CHILD = (1 << 6),
DEG_TAG_PSYS_PHYS = (1 << 7),
DEG_TAG_PSYS = ((1 << 3) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7)),
@@ -167,6 +167,9 @@ enum {
DEG_TAG_SHADING_UPDATE = (1 << 9),
DEG_TAG_SELECT_UPDATE = (1 << 10),
DEG_TAG_BASE_FLAGS_UPDATE = (1 << 11),
+
+ /* Only inform editors about the change. Don't modify datablock itself. */
+ DEG_TAG_EDITORS_UPDATE = (1 << 12),
};
void DEG_id_tag_update(struct ID *id, int flag);
void DEG_id_tag_update_ex(struct Main *bmain, struct ID *id, int flag);
@@ -176,10 +179,9 @@ void DEG_graph_id_tag_update(struct Main *bmain,
struct ID *id,
int flag);
-/* Tag given ID type for update.
- *
- * Used by all sort of render engines to quickly check if
- * IDs of a given type need to be checked for update.
+/* 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.
*/
void DEG_id_type_tag(struct Main *bmain, short id_type);
@@ -195,6 +197,7 @@ void DEG_graph_flush_update(struct Main *bmain, Depsgraph *depsgraph);
*/
void DEG_ids_check_recalc(struct Main *bmain,
struct Scene *scene,
+ struct ViewLayer *view_layer,
bool time);
/* ************************************************ */
@@ -214,7 +217,7 @@ void DEG_evaluation_context_init(struct EvaluationContext *eval_ctx,
void DEG_evaluation_context_init_from_scene(struct EvaluationContext *eval_ctx,
struct Scene *scene,
struct ViewLayer *view_layer,
- struct RenderEngineType *engine,
+ struct RenderEngineType *engine_type,
eEvaluationMode mode);
/* Free evaluation context. */
@@ -245,20 +248,21 @@ bool DEG_needs_eval(Depsgraph *graph);
* to do their own updates based on changes.
*/
-typedef void (*DEG_EditorUpdateIDCb)(struct Main *bmain, struct ID *id);
-typedef void (*DEG_EditorUpdateSceneCb)(struct Main *bmain,
- struct Scene *scene,
- int updated);
-typedef void (*DEG_EditorUpdateScenePreCb)(struct Main *bmain,
- struct Scene *scene,
- bool time);
+typedef struct DEGEditorUpdateContext {
+ struct Main *bmain;
+ struct Scene *scene;
+ struct ViewLayer *view_layer;
+} DEGEditorUpdateContext;
+
+typedef void (*DEG_EditorUpdateIDCb)(
+ const DEGEditorUpdateContext *update_ctx,
+ struct ID *id);
+typedef void (*DEG_EditorUpdateSceneCb)(
+ const DEGEditorUpdateContext *update_ctx, int updated);
/* Set callbacks which are being called when depsgraph changes. */
void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func,
- DEG_EditorUpdateSceneCb scene_func,
- DEG_EditorUpdateScenePreCb scene_pre_func);
-
-void DEG_editors_update_pre(struct Main *bmain, struct Scene *scene, bool time);
+ DEG_EditorUpdateSceneCb scene_func);
#ifdef __cplusplus
} /* extern "C" */
diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h
index 36d44a06eac..7771d35d581 100644
--- a/source/blender/depsgraph/DEG_depsgraph_query.h
+++ b/source/blender/depsgraph/DEG_depsgraph_query.h
@@ -67,16 +67,16 @@ struct Object *DEG_get_evaluated_object(struct Depsgraph *depsgraph, struct Obje
/* Get evaluated version of given ID datablock. */
struct ID *DEG_get_evaluated_id(struct Depsgraph *depsgraph, struct ID *id);
-/* ************************ DAG iterators ********************* */
+/* ************************ DEG iterators ********************* */
enum {
- DEG_OBJECT_ITER_FLAG_SET = (1 << 0),
- DEG_OBJECT_ITER_FLAG_DUPLI = (1 << 1),
-};
+ DEG_ITER_OBJECT_FLAG_SET = (1 << 0),
+ DEG_ITER_OBJECT_FLAG_DUPLI = (1 << 1),
-#define DEG_OBJECT_ITER_FLAG_ALL (DEG_OBJECT_ITER_FLAG_SET | DEG_OBJECT_ITER_FLAG_DUPLI)
+ DEG_ITER_OBJECT_FLAG_ALL = (DEG_ITER_OBJECT_FLAG_SET | DEG_ITER_OBJECT_FLAG_DUPLI),
+};
-typedef struct DEGObjectsIteratorData {
+typedef struct DEGOIterObjectData {
struct Depsgraph *graph;
struct Scene *scene;
struct EvaluationContext eval_ctx;
@@ -103,28 +103,40 @@ typedef struct DEGObjectsIteratorData {
/* **** Iteration ober ID nodes **** */
size_t id_node_index;
size_t num_id_nodes;
-} DEGObjectsIteratorData;
+} DEGOIterObjectData;
-void DEG_objects_iterator_begin(struct BLI_Iterator *iter, DEGObjectsIteratorData *data);
-void DEG_objects_iterator_next(struct BLI_Iterator *iter);
-void DEG_objects_iterator_end(struct BLI_Iterator *iter);
+void DEG_iterator_objects_begin(struct BLI_Iterator *iter, DEGOIterObjectData *data);
+void DEG_iterator_objects_next(struct BLI_Iterator *iter);
+void DEG_iterator_objects_end(struct BLI_Iterator *iter);
#define DEG_OBJECT_ITER(graph_, instance_, flag_) \
{ \
- DEGObjectsIteratorData data_ = { \
+ DEGOIterObjectData data_ = { \
.graph = (graph_), \
.flag = (flag_), \
}; \
\
- ITER_BEGIN(DEG_objects_iterator_begin, \
- DEG_objects_iterator_next, \
- DEG_objects_iterator_end, \
+ ITER_BEGIN(DEG_iterator_objects_begin, \
+ DEG_iterator_objects_next, \
+ DEG_iterator_objects_end, \
&data_, Object *, instance_)
#define DEG_OBJECT_ITER_END \
ITER_END \
}
+/* ************************ DEG traversal ********************* */
+
+typedef void (*DEGForeachIDCallback)(ID *id, void *user_data);
+
+/* NOTE: Modifies runtime flags in depsgraph nodes, so can not be used in
+ * parallel. Keep an eye on that!
+ */
+void DEG_foreach_dependent_ID(const Depsgraph *depsgraph,
+ const ID *id,
+ DEGForeachIDCallback callback, void *user_data);
+
+
#ifdef __cplusplus
} /* extern "C" */
#endif
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc
index d6a054f2ee9..20a93673350 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder.cc
@@ -55,12 +55,6 @@ void deg_graph_build_finalize(Main *bmain, Depsgraph *graph)
if ((id->tag & LIB_TAG_ID_RECALC_ALL)) {
id_node->tag_update(graph);
}
- else if (GS(id->name) == ID_OB) {
- Object *object = (Object *)id;
- if (object->recalc & OB_RECALC_ALL) {
- id_node->tag_update(graph);
- }
- }
/* TODO(sergey): This is not ideal at all, since this forces
* re-evaluaiton of the whole tree.
*/
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index a2a0f633fd9..8fbd1e7a46d 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -180,7 +180,7 @@ DepsgraphNodeBuilder::~DepsgraphNodeBuilder()
IDDepsNode *DepsgraphNodeBuilder::add_id_node(ID *id, bool do_tag)
{
if (!DEG_depsgraph_use_copy_on_write()) {
- return graph_->add_id_node(id);
+ return graph_->add_id_node(id, do_tag);
}
IDDepsNode *id_node = NULL;
ID *id_cow = (ID *)BLI_ghash_lookup(cow_id_hash_, id);
@@ -428,9 +428,11 @@ void DepsgraphNodeBuilder::build_group(Group *group)
}
group_id->tag |= LIB_TAG_DOIT;
- LINKLIST_FOREACH (GroupObject *, go, &group->gobject) {
- build_object(NULL, go->ob, DEG_ID_LINKED_INDIRECTLY);
+ LINKLIST_FOREACH(Base *, base, &group->view_layer->object_bases) {
+ build_object(NULL, base->object, DEG_ID_LINKED_INDIRECTLY);
}
+
+ build_view_layer_collections(&group->id, group->view_layer);
}
void DepsgraphNodeBuilder::build_object(Base *base,
@@ -583,7 +585,6 @@ void DepsgraphNodeBuilder::build_object_transform(Object *object)
op_node = add_operation_node(&object->id, DEG_NODE_TYPE_TRANSFORM,
function_bind(BKE_object_eval_local_transform,
_1,
- scene_cow,
ob_cow),
DEG_OPCODE_TRANSFORM_LOCAL);
op_node->set_as_entry();
@@ -607,7 +608,6 @@ void DepsgraphNodeBuilder::build_object_transform(Object *object)
add_operation_node(&object->id, DEG_NODE_TYPE_TRANSFORM,
function_bind(BKE_object_eval_uber_transform,
_1,
- scene_cow,
ob_cow),
DEG_OPCODE_TRANSFORM_OBJECT_UBEREVAL);
@@ -804,8 +804,8 @@ void DepsgraphNodeBuilder::build_rigidbody(Scene *scene)
/* objects - simulation participants */
if (rbw->group) {
- LINKLIST_FOREACH (GroupObject *, go, &rbw->group->gobject) {
- Object *object = go->ob;
+ LINKLIST_FOREACH (Base *, base, &rbw->group->view_layer->object_bases) {
+ Object *object = base->object;
if (!object || (object->type != OB_MESH))
continue;
@@ -1241,6 +1241,9 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree)
* pipeline. No need to build dependencies for them here.
*/
}
+ else if (id_type == ID_TXT) {
+ /* Ignore script nodes. */
+ }
else if (bnode->type == NODE_GROUP) {
bNodeTree *group_ntree = (bNodeTree *)id;
if ((group_ntree->id.tag & LIB_TAG_DOIT) == 0) {
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
index 5c0a5054590..c9bdd194227 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
@@ -208,11 +208,13 @@ struct DepsgraphNodeBuilder {
int index;
LayerCollection *parent;
};
- void build_layer_collection(LayerCollection *layer_collection,
+ void build_layer_collection(ID *owner_id,
+ LayerCollection *layer_collection,
LayerCollectionState *state);
- void build_layer_collections(ListBase *layer_collections,
+ void build_layer_collections(ID *owner_id,
+ ListBase *layer_collections,
LayerCollectionState *state);
- void build_view_layer_collections(Scene *scene, ViewLayer *view_layer);
+ void build_view_layer_collections(ID *owner_id, ViewLayer *view_layer);
protected:
struct SavedEntryTag {
ID *id;
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_layer_collection.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_layer_collection.cc
index 4d4bf2e4ffe..79316e47022 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_layer_collection.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_layer_collection.cc
@@ -24,7 +24,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/builder/deg_builder_nodes_layer.cc
+/** \file blender/depsgraph/intern/builder/deg_builder_nodes_layer_collection.cc
* \ingroup depsgraph
*
* Methods for constructing depsgraph's nodes
@@ -62,6 +62,7 @@ extern "C" {
namespace DEG {
void DepsgraphNodeBuilder::build_layer_collection(
+ ID *owner_id,
LayerCollection *layer_collection,
LayerCollectionState *state)
{
@@ -69,7 +70,7 @@ void DepsgraphNodeBuilder::build_layer_collection(
* Harmless but could be optimized.
*/
ComponentDepsNode *comp = add_component_node(
- &scene_->id,
+ owner_id,
DEG_NODE_TYPE_LAYER_COLLECTIONS);
add_operation_node(comp,
@@ -85,31 +86,32 @@ void DepsgraphNodeBuilder::build_layer_collection(
/* Recurs into nested layer collections. */
LayerCollection *parent = state->parent;
state->parent = layer_collection;
- build_layer_collections(&layer_collection->layer_collections, state);
+ build_layer_collections(owner_id, &layer_collection->layer_collections, state);
state->parent = parent;
}
-void DepsgraphNodeBuilder::build_layer_collections(ListBase *layer_collections,
+void DepsgraphNodeBuilder::build_layer_collections(ID *owner_id,
+ ListBase *layer_collections,
LayerCollectionState *state)
{
LINKLIST_FOREACH (LayerCollection *, layer_collection, layer_collections) {
- build_layer_collection(layer_collection, state);
+ build_layer_collection(owner_id, layer_collection, state);
}
}
void DepsgraphNodeBuilder::build_view_layer_collections(
- Scene *scene,
+ ID *owner_id,
ViewLayer *view_layer)
{
LayerCollectionState state;
state.index = 0;
ComponentDepsNode *comp = add_component_node(
- &scene_->id,
+ owner_id,
DEG_NODE_TYPE_LAYER_COLLECTIONS);
add_operation_node(comp,
function_bind(BKE_layer_eval_layer_collection_pre,
_1,
- scene,
+ owner_id,
view_layer),
DEG_OPCODE_VIEW_LAYER_INIT);
add_operation_node(comp,
@@ -118,7 +120,7 @@ void DepsgraphNodeBuilder::build_view_layer_collections(
view_layer),
DEG_OPCODE_VIEW_LAYER_DONE);
state.parent = NULL;
- build_layer_collections(&view_layer->layer_collections, &state);
+ build_layer_collections(owner_id, &view_layer->layer_collections, &state);
}
} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
index c4542660c8b..531ea55cf5c 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
@@ -248,9 +248,9 @@ void DepsgraphNodeBuilder::build_rig(Object *object)
/* bones */
LINKLIST_FOREACH (bPoseChannel *, pchan, &object_cow->pose->chanbase) {
- /* node for bone eval */
- op_node = add_operation_node(&object->id, DEG_NODE_TYPE_BONE,
- pchan->name, NULL, DEG_OPCODE_BONE_LOCAL);
+ /* Node for bone evaluation. */
+ op_node = add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name, NULL,
+ DEG_OPCODE_BONE_LOCAL);
op_node->set_as_entry();
add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name,
@@ -269,6 +269,14 @@ void DepsgraphNodeBuilder::build_rig(Object *object)
function_bind(BKE_pose_bone_done, _1, pchan),
DEG_OPCODE_BONE_DONE);
op_node->set_as_exit();
+ /* Custom properties. */
+ if (pchan->prop != NULL) {
+ add_operation_node(&object->id,
+ DEG_NODE_TYPE_PARAMETERS,
+ NULL,
+ DEG_OPCODE_PARAMETERS_EVAL,
+ pchan->name);
+ }
/* Build constraints. */
if (pchan->constraints.first != NULL) {
build_pose_constraints(object, pchan);
@@ -311,17 +319,26 @@ void DepsgraphNodeBuilder::build_rig(Object *object)
void DepsgraphNodeBuilder::build_proxy_rig(Object *object)
{
- ID *obdata = (ID *)object->data;
+ bArmature *arm = (bArmature *)object->data;
OperationDepsNode *op_node;
- Object *object_cow = get_cow_datablock(object);
+ Object *object_cow;
+ if (DEG_depsgraph_use_copy_on_write()) {
+ /* NOTE: We need to expand both object and armature, so this way we can
+ * safely create object level pose.
+ */
+ object_cow = expand_cow_datablock(object);
+ }
+ else {
+ object_cow = object;
+ }
/* Sanity check. */
BLI_assert(object->pose != NULL);
/* Animation. */
- build_animdata(obdata);
+ build_animdata(&arm->id);
/* speed optimization for animation lookups */
BKE_pose_channels_hash_make(object->pose);
- if (object->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
- BKE_pose_update_constraint_flags(object->pose);
+ if (object_cow->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
+ BKE_pose_update_constraint_flags(object_cow->pose);
}
op_node = add_operation_node(&object->id,
DEG_NODE_TYPE_EVAL_POSE,
@@ -330,7 +347,7 @@ void DepsgraphNodeBuilder::build_proxy_rig(Object *object)
object_cow),
DEG_OPCODE_POSE_INIT);
op_node->set_as_entry();
- LINKLIST_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
+ LINKLIST_FOREACH (bPoseChannel *, pchan, &object_cow->pose->chanbase) {
/* Local bone transform. */
op_node = add_operation_node(&object->id,
DEG_NODE_TYPE_BONE,
@@ -351,6 +368,15 @@ void DepsgraphNodeBuilder::build_proxy_rig(Object *object)
NULL,
DEG_OPCODE_BONE_DONE);
op_node->set_as_exit();
+
+ /* Custom properties. */
+ if (pchan->prop != NULL) {
+ add_operation_node(&object->id,
+ DEG_NODE_TYPE_PARAMETERS,
+ NULL,
+ DEG_OPCODE_PARAMETERS_EVAL,
+ pchan->name);
+ }
}
op_node = add_operation_node(&object->id,
DEG_NODE_TYPE_EVAL_POSE,
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc
index c7966af76c6..49772c4f852 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc
@@ -24,7 +24,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc
+/** \file blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc
* \ingroup depsgraph
*
* Methods for constructing depsgraph's nodes
@@ -65,13 +65,35 @@ extern "C" {
namespace DEG {
-void DepsgraphNodeBuilder::build_view_layer(Scene *scene,
- ViewLayer *view_layer,
- eDepsNode_LinkedState_Type linked_state)
+void DepsgraphNodeBuilder::build_view_layer(
+ Scene *scene,
+ ViewLayer *view_layer,
+ eDepsNode_LinkedState_Type linked_state)
{
+ /* Scene ID block. */
+ add_id_node(&scene->id);
+ /* Time source. */
+ add_time_source();
+ /* Setup currently building context. */
+ scene_ = scene;
+ /* Expand Scene Cow datablock to get proper pointers to bases. */
Scene *scene_cow;
ViewLayer *view_layer_cow;
if (DEG_depsgraph_use_copy_on_write()) {
+ /* NOTE: We need to create ID nodes for all objects coming from bases,
+ * otherwise remapping will not replace objects with their CoW versions
+ * for CoW bases.
+ */
+ LINKLIST_FOREACH(Base *, base, &view_layer->object_bases) {
+ Object *object = base->object;
+ add_id_node(&object->id, false);
+ }
+ /* Create ID node for nested ID of nodetree as well, otherwise remapping
+ * will not work correct either.
+ */
+ if (scene->nodetree != NULL) {
+ add_id_node(&scene->nodetree->id, false);
+ }
/* Make sure we've got ID node, so we can get pointer to CoW datablock.
*/
scene_cow = expand_cow_datablock(scene);
@@ -84,80 +106,64 @@ void DepsgraphNodeBuilder::build_view_layer(Scene *scene,
scene_cow = scene;
view_layer_cow = view_layer;
}
-
- /* scene ID block */
- add_id_node(&scene->id);
-
- /* timesource */
- add_time_source();
-
- /* Setup currently building context. */
- scene_ = scene;
-
- /* scene objects */
+ /* Scene objects. */
int select_color = 1;
- LINKLIST_FOREACH(Base *, base, &view_layer_cow->object_bases) {
+ /* NOTE: Base is used for function bindings as-is, so need to pass CoW base,
+ * but object is expected to be an original one. Hence we go into some
+ * tricks here iterating over the view layer.
+ */
+ for (Base *base_orig = (Base *)view_layer->object_bases.first,
+ *base_cow = (Base *)view_layer_cow->object_bases.first;
+ base_orig != NULL;
+ base_orig = base_orig->next, base_cow = base_cow->next)
+ {
/* object itself */
- build_object(base, base->object, linked_state);
- base->object->select_color = select_color++;
+ build_object(base_cow, base_orig->object, linked_state);
+ base_orig->object->select_color = select_color++;
}
if (scene->camera != NULL) {
- build_object(NULL, scene->camera, linked_state);
+ build_object(NULL, scene->camera, DEG_ID_LINKED_INDIRECTLY);
}
-
- /* rigidbody */
- if (scene->rigidbody_world) {
+ /* Rigidbody. */
+ if (scene->rigidbody_world != NULL) {
build_rigidbody(scene);
}
-
- /* scene's animation and drivers */
- if (scene->adt) {
+ /* Scene's animation and drivers. */
+ if (scene->adt != NULL) {
build_animdata(&scene->id);
}
-
- /* world */
- if (scene->world) {
+ /* World. */
+ if (scene->world != NULL) {
build_world(scene->world);
}
-
- /* compo nodes */
- if (scene->nodetree) {
+ /* Compositor nodes */
+ if (scene->nodetree != NULL) {
build_compositor(scene);
}
-
- /* sequencer */
- // XXX...
-
- /* grease pencil */
- if (scene->gpd) {
+ /* Grease pencil. */
+ if (scene->gpd != NULL) {
build_gpencil(scene->gpd);
}
-
/* Cache file. */
LINKLIST_FOREACH (CacheFile *, cachefile, &bmain_->cachefiles) {
build_cachefile(cachefile);
}
-
/* Masks. */
LINKLIST_FOREACH (Mask *, mask, &bmain_->mask) {
build_mask(mask);
}
-
/* Movie clips. */
LINKLIST_FOREACH (MovieClip *, clip, &bmain_->movieclip) {
build_movieclip(clip);
}
-
/* Collections. */
- build_view_layer_collections(scene_cow, view_layer_cow);
-
+ build_view_layer_collections(&scene->id, view_layer_cow);
/* Parameters evaluation for scene relations mainly. */
add_operation_node(&scene->id,
DEG_NODE_TYPE_PARAMETERS,
NULL,
DEG_OPCODE_PLACEHOLDER,
"Scene Eval");
-
/* Build all set scenes. */
if (scene->set != NULL) {
ViewLayer *set_view_layer = BKE_view_layer_from_scene_get(scene->set);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index f2805cc9a7c..14dedef2601 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -120,10 +120,10 @@ struct BuilderWalkUserData {
DepsgraphRelationBuilder *builder;
};
-static void modifier_walk(void *user_data,
- struct Object * /*object*/,
- struct Object **obpoin,
- int /*cb_flag*/)
+void modifier_walk(void *user_data,
+ struct Object * /*object*/,
+ struct Object **obpoin,
+ int /*cb_flag*/)
{
BuilderWalkUserData *data = (BuilderWalkUserData *)user_data;
if (*obpoin) {
@@ -203,20 +203,6 @@ static bool object_particles_depends_on_time(Object *object)
/* **** General purpose functions **** */
-RNAPathKey::RNAPathKey(ID *id, const char *path) :
- id(id)
-{
- /* create ID pointer for root of path lookup */
- PointerRNA id_ptr;
- RNA_id_pointer_create(id, &id_ptr);
- /* try to resolve path... */
- int index;
- if (!RNA_path_resolve_full(&id_ptr, path, &this->ptr, &this->prop, &index)) {
- this->ptr = PointerRNA_NULL;
- this->prop = NULL;
- }
-}
-
DepsgraphRelationBuilder::DepsgraphRelationBuilder(Main *bmain,
Depsgraph *graph)
: bmain_(bmain),
@@ -289,10 +275,11 @@ bool DepsgraphRelationBuilder::has_node(const OperationKey &key) const
void DepsgraphRelationBuilder::add_time_relation(TimeSourceDepsNode *timesrc,
DepsNode *node_to,
- const char *description)
+ const char *description,
+ bool check_unique)
{
if (timesrc && node_to) {
- graph_->add_new_relation(timesrc, node_to, description);
+ graph_->add_new_relation(timesrc, node_to, description, check_unique);
}
else {
DEG_DEBUG_PRINTF("add_time_relation(%p = %s, %p = %s, %s) Failed\n",
@@ -305,10 +292,11 @@ void DepsgraphRelationBuilder::add_time_relation(TimeSourceDepsNode *timesrc,
void DepsgraphRelationBuilder::add_operation_relation(
OperationDepsNode *node_from,
OperationDepsNode *node_to,
- const char *description)
+ const char *description,
+ bool check_unique)
{
if (node_from && node_to) {
- graph_->add_new_relation(node_from, node_to, description);
+ graph_->add_new_relation(node_from, node_to, description, check_unique);
}
else {
DEG_DEBUG_PRINTF("add_operation_relation(%p = %s, %p = %s, %s) Failed\n",
@@ -318,13 +306,22 @@ void DepsgraphRelationBuilder::add_operation_relation(
}
}
-void DepsgraphRelationBuilder::add_collision_relations(const OperationKey &key, Scene *scene, Object *object, Group *group, bool dupli, const char *name)
+void DepsgraphRelationBuilder::add_collision_relations(
+ const OperationKey &key,
+ Scene *scene,
+ Object *object,
+ Group *group,
+ bool dupli,
+ const char *name)
{
unsigned int numcollobj;
- Object **collobjs = get_collisionobjects_ext(scene, object, group, &numcollobj, eModifierType_Collision, dupli);
-
- for (unsigned int i = 0; i < numcollobj; i++)
- {
+ Object **collobjs = get_collisionobjects_ext(scene,
+ object,
+ group,
+ &numcollobj,
+ eModifierType_Collision,
+ dupli);
+ for (unsigned int i = 0; i < numcollobj; i++) {
Object *ob1 = collobjs[i];
ComponentKey trf_key(&ob1->id, DEG_NODE_TYPE_TRANSFORM);
@@ -333,47 +330,62 @@ void DepsgraphRelationBuilder::add_collision_relations(const OperationKey &key,
ComponentKey coll_key(&ob1->id, DEG_NODE_TYPE_GEOMETRY);
add_relation(coll_key, key, name);
}
-
- if (collobjs)
+ if (collobjs != NULL) {
MEM_freeN(collobjs);
+ }
}
-void DepsgraphRelationBuilder::add_forcefield_relations(const OperationKey &key, Scene *scene, Object *object, ParticleSystem *psys, EffectorWeights *eff, bool add_absorption, const char *name)
+void DepsgraphRelationBuilder::add_forcefield_relations(
+ const OperationKey &key,
+ Scene *scene,
+ Object *object,
+ ParticleSystem *psys,
+ EffectorWeights *eff,
+ bool add_absorption,
+ const char *name)
{
ListBase *effectors = pdInitEffectors(NULL, scene, object, psys, eff, false);
-
- if (effectors) {
- for (EffectorCache *eff = (EffectorCache *)effectors->first; eff; eff = eff->next) {
+ if (effectors != NULL) {
+ LINKLIST_FOREACH(EffectorCache *, eff, effectors) {
if (eff->ob != object) {
ComponentKey eff_key(&eff->ob->id, DEG_NODE_TYPE_TRANSFORM);
add_relation(eff_key, key, name);
}
-
- if (eff->psys) {
+ if (eff->psys != NULL) {
if (eff->ob != object) {
ComponentKey eff_key(&eff->ob->id, DEG_NODE_TYPE_EVAL_PARTICLES);
add_relation(eff_key, key, name);
- /* TODO: remove this when/if EVAL_PARTICLES is sufficient for up to date particles */
+ /* TODO: remove this when/if EVAL_PARTICLES is sufficient
+ * for up to date particles.
+ */
ComponentKey mod_key(&eff->ob->id, DEG_NODE_TYPE_GEOMETRY);
add_relation(mod_key, key, name);
}
else if (eff->psys != psys) {
- OperationKey eff_key(&eff->ob->id, DEG_NODE_TYPE_EVAL_PARTICLES, DEG_OPCODE_PARTICLE_SYSTEM_EVAL, eff->psys->name);
+ OperationKey eff_key(&eff->ob->id,
+ DEG_NODE_TYPE_EVAL_PARTICLES,
+ DEG_OPCODE_PARTICLE_SYSTEM_EVAL,
+ eff->psys->name);
add_relation(eff_key, key, name);
}
}
-
if (eff->pd->forcefield == PFIELD_SMOKEFLOW && eff->pd->f_source) {
- ComponentKey trf_key(&eff->pd->f_source->id, DEG_NODE_TYPE_TRANSFORM);
+ ComponentKey trf_key(&eff->pd->f_source->id,
+ DEG_NODE_TYPE_TRANSFORM);
add_relation(trf_key, key, "Smoke Force Domain");
- ComponentKey eff_key(&eff->pd->f_source->id, DEG_NODE_TYPE_GEOMETRY);
+ ComponentKey eff_key(&eff->pd->f_source->id,
+ DEG_NODE_TYPE_GEOMETRY);
add_relation(eff_key, key, "Smoke Force Domain");
}
-
if (add_absorption && (eff->pd->flag & PFIELD_VISIBILITY)) {
- add_collision_relations(key, scene, object, NULL, true, "Force Absorption");
+ add_collision_relations(key,
+ scene,
+ object,
+ NULL,
+ true,
+ "Force Absorption");
}
}
}
@@ -413,14 +425,20 @@ void DepsgraphRelationBuilder::build_group(Object *object, Group *group)
OperationKey object_local_transform_key(&object->id,
DEG_NODE_TYPE_TRANSFORM,
DEG_OPCODE_TRANSFORM_LOCAL);
- LINKLIST_FOREACH (GroupObject *, go, &group->gobject) {
- if (!group_done) {
- build_object(NULL, go->ob);
+
+ if (!group_done) {
+ LINKLIST_FOREACH(Base *, base, &group->view_layer->object_bases) {
+ build_object(NULL, base->object);
}
- ComponentKey dupli_transform_key(&go->ob->id, DEG_NODE_TYPE_TRANSFORM);
+
+ build_view_layer_collections(&group->id, group->view_layer);
+ group_id->tag |= LIB_TAG_DOIT;
+ }
+
+ LINKLIST_FOREACH (Base *, base, &group->view_layer->object_bases) {
+ ComponentKey dupli_transform_key(&base->object->id, DEG_NODE_TYPE_TRANSFORM);
add_relation(dupli_transform_key, object_local_transform_key, "Dupligroup");
}
- group_id->tag |= LIB_TAG_DOIT;
}
void DepsgraphRelationBuilder::build_object(Base *base, Object *object)
@@ -457,7 +475,7 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object)
/* Local -> parent. */
add_relation(local_transform_key,
parent_transform_key,
- "[ObLocal -> ObParent]");
+ "ObLocal -> ObParent");
}
/* Modifiers. */
if (object->modifiers.first != NULL) {
@@ -483,8 +501,8 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object)
&object->constraints,
NULL);
/* operation order */
- add_relation(base_op_key, constraint_key, "[ObBase-> Constraint Stack]");
- add_relation(constraint_key, final_transform_key, "[ObConstraints -> Done]");
+ add_relation(base_op_key, constraint_key, "ObBase-> Constraint Stack");
+ add_relation(constraint_key, final_transform_key, "ObConstraints -> Done");
// XXX
add_relation(constraint_key, ob_ubereval_key, "Temp Ubereval");
add_relation(ob_ubereval_key, final_transform_key, "Temp Ubereval");
@@ -504,11 +522,6 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object)
}
/* Animation data */
build_animdata(&object->id);
- // XXX: This should be hooked up by the build_animdata code
- if (needs_animdata_node(&object->id)) {
- ComponentKey adt_key(&object->id, DEG_NODE_TYPE_ANIMATION);
- add_relation(adt_key, local_transform_key, "Object Animation");
- }
/* Object data. */
build_object_data(object);
/* Particle systems. */
@@ -747,14 +760,14 @@ void DepsgraphRelationBuilder::build_constraints(ID *id,
* Constraint dependency chain.
*/
TimeSourceKey time_src_key;
- add_relation(time_src_key, constraint_op_key, "[TimeSrc -> Animation]");
+ add_relation(time_src_key, constraint_op_key, "TimeSrc -> Animation");
}
else if (cti->type == CONSTRAINT_TYPE_TRANSFORM_CACHE) {
/* TODO(kevin): This is more a TimeSource -> CacheFile -> Constraint
* dependency chain.
*/
TimeSourceKey time_src_key;
- add_relation(time_src_key, constraint_op_key, "[TimeSrc -> Animation]");
+ add_relation(time_src_key, constraint_op_key, "TimeSrc -> Animation");
bTransformCacheConstraint *data = (bTransformCacheConstraint *)con->data;
if (data->cache_file) {
ComponentKey cache_key(&data->cache_file->id, DEG_NODE_TYPE_CACHE);
@@ -908,25 +921,85 @@ void DepsgraphRelationBuilder::build_constraints(ID *id,
void DepsgraphRelationBuilder::build_animdata(ID *id)
{
- AnimData *adt = BKE_animdata_from_id(id);
+ /* Animation curves and NLA. */
+ build_animdata_curves(id);
+ /* Drivers. */
+ build_animdata_drievrs(id);
+}
- if (adt == NULL)
+void DepsgraphRelationBuilder::build_animdata_curves(ID *id)
+{
+ AnimData *adt = BKE_animdata_from_id(id);
+ if (adt == NULL) {
return;
-
+ }
+ if (adt->action == NULL && adt->nla_tracks.first == NULL) {
+ return;
+ }
+ /* Wire up dependency to time source. */
ComponentKey adt_key(id, DEG_NODE_TYPE_ANIMATION);
+ TimeSourceKey time_src_key;
+ add_relation(time_src_key, adt_key, "TimeSrc -> Animation");
+ /* Build relations from animation operation to properties it changes. */
+ build_animdata_curves_targets(id);
+}
- /* animation */
- if (adt->action || adt->nla_tracks.first) {
- /* wire up dependency to time source */
- TimeSourceKey time_src_key;
- add_relation(time_src_key, adt_key, "[TimeSrc -> Animation]");
-
- // XXX: Hook up specific update callbacks for special properties which may need it...
-
- // XXX: animdata "hierarchy" - top-level overrides need to go after lower-down
+void DepsgraphRelationBuilder::build_animdata_curves_targets(ID *id)
+{
+ AnimData *adt = BKE_animdata_from_id(id);
+ if (adt == NULL || adt->action == NULL) {
+ return;
+ }
+ /* Get source operation. */
+ ComponentKey adt_key(id, DEG_NODE_TYPE_ANIMATION);
+ DepsNode *node_from = get_node(adt_key);
+ BLI_assert(node_from != NULL);
+ if (node_from == NULL) {
+ return;
}
+ OperationDepsNode *operation_from = node_from->get_exit_operation();
+ BLI_assert(operation_from != NULL);
+ /* Iterate over all curves and build relations. */
+ PointerRNA id_ptr;
+ RNA_id_pointer_create(id, &id_ptr);
+ LINKLIST_FOREACH(FCurve *, fcu, &adt->action->curves) {
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index;
+ if (!RNA_path_resolve_full(&id_ptr, fcu->rna_path,
+ &ptr, &prop, &index))
+ {
+ continue;
+ }
+ DepsNode *node_to = graph_->find_node_from_pointer(&ptr, prop);
+ if (node_to == NULL) {
+ continue;
+ }
+ OperationDepsNode *operation_to = node_to->get_entry_operation();
+ /* NOTE: Special case for bones, avoid relation from animation to
+ * each of the bones. Bone evaluation could only start from pose
+ * init anyway.
+ */
+ if (operation_to->opcode == DEG_OPCODE_BONE_LOCAL) {
+ OperationKey pose_init_key(id,
+ DEG_NODE_TYPE_EVAL_POSE,
+ DEG_OPCODE_POSE_INIT);
+ add_relation(adt_key, pose_init_key, "Animation -> Prop", true);
+ continue;
+ }
+ graph_->add_new_relation(operation_from, operation_to,
+ "Animation -> Prop",
+ true);
+ }
+}
- /* drivers */
+void DepsgraphRelationBuilder::build_animdata_drievrs(ID *id)
+{
+ AnimData *adt = BKE_animdata_from_id(id);
+ if (adt == NULL) {
+ return;
+ }
+ ComponentKey adt_key(id, DEG_NODE_TYPE_ANIMATION);
LINKLIST_FOREACH (FCurve *, fcu, &adt->drivers) {
OperationKey driver_key(id,
DEG_NODE_TYPE_PARAMETERS,
@@ -979,13 +1052,13 @@ void DepsgraphRelationBuilder::build_animdata(ID *id)
DEG_OPCODE_DRIVER,
fcu->rna_path ? fcu->rna_path : "",
fcu->array_index);
- add_relation(prev_driver_key, driver_key, "[Driver Order]");
+ add_relation(prev_driver_key, driver_key, "Driver Order");
}
}
/* prevent driver from occurring before own animation... */
if (adt->action || adt->nla_tracks.first) {
- add_relation(adt_key, driver_key, "[AnimData Before Drivers]");
+ add_relation(adt_key, driver_key, "AnimData Before Drivers");
}
}
}
@@ -998,45 +1071,34 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
DEG_OPCODE_DRIVER,
fcu->rna_path ? fcu->rna_path : "",
fcu->array_index);
- bPoseChannel *pchan = NULL;
- const char *rna_path = fcu->rna_path ? fcu->rna_path : "";
- const ID_Type id_type = GS(id->name);
-
- /* Create dependency between driver and data affected by it. */
- /* - direct property relationship... */
- //RNAPathKey affected_key(id, fcu->rna_path);
- //add_relation(driver_key, affected_key, "[Driver -> Data] DepsRel");
-
/* Driver -> data components (for interleaved evaluation
* bones/constraints/modifiers).
*/
- // XXX: this probably should probably be moved out into a separate function.
- if (strstr(rna_path, "pose.bones[") != NULL) {
- /* interleaved drivers during bone eval */
- /* TODO: ideally, if this is for a constraint, it goes to said
- * constraint.
- */
- Object *object = (Object *)id;
- char *bone_name = BLI_str_quoted_substrN(rna_path, "pose.bones[");
- pchan = BKE_pose_channel_find_name(object->pose, bone_name);
- if (bone_name != NULL) {
- MEM_freeN(bone_name);
- bone_name = NULL;
- }
- if (pchan != NULL) {
- OperationKey bone_key(id,
- DEG_NODE_TYPE_BONE,
- pchan->name,
- DEG_OPCODE_BONE_LOCAL);
- add_relation(driver_key, bone_key, "[Driver -> Bone]");
- }
- else {
- fprintf(stderr,
- "Couldn't find bone name for driver path - '%s'\n",
- rna_path);
- }
+ build_driver_data(id, fcu);
+ /* Loop over variables to get the target relationships. */
+ build_driver_variables(id, fcu);
+ /* It's quite tricky to detect if the driver actually depends on time or
+ * not, so for now we'll be quite conservative here about optimization and
+ * consider all python drivers to be depending on time.
+ */
+ if ((driver->type == DRIVER_TYPE_PYTHON) &&
+ python_driver_depends_on_time(driver))
+ {
+ TimeSourceKey time_src_key;
+ add_relation(time_src_key, driver_key, "TimeSrc -> Driver");
}
- else if (id_type == ID_AR && strstr(rna_path, "bones[")) {
+}
+
+void DepsgraphRelationBuilder::build_driver_data(ID *id, FCurve *fcu)
+{
+ OperationKey driver_key(id,
+ DEG_NODE_TYPE_PARAMETERS,
+ DEG_OPCODE_DRIVER,
+ fcu->rna_path ? fcu->rna_path : "",
+ fcu->array_index);
+ const char *rna_path = fcu->rna_path ? fcu->rna_path : "";
+ const RNAPathKey self_key(id, rna_path);
+ if (GS(id->name) == ID_AR && strstr(rna_path, "bones[")) {
/* Drivers on armature-level bone settings (i.e. bbone stuff),
* which will affect the evaluation of corresponding pose bones.
*/
@@ -1061,7 +1123,7 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
DEG_OPCODE_BONE_LOCAL);
add_relation(driver_key,
bone_key,
- "[Arm Bone -> Driver -> Bone]");
+ "Arm Bone -> Driver -> Bone");
}
}
}
@@ -1075,71 +1137,23 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
rna_path);
}
}
- else if (id_type == ID_OB && strstr(rna_path, "modifiers[")) {
- OperationKey modifier_key(id,
- DEG_NODE_TYPE_GEOMETRY,
- DEG_OPCODE_GEOMETRY_UBEREVAL);
- if (has_node(modifier_key)) {
- add_relation(driver_key, modifier_key, "[Driver -> Modifier]");
- }
- else {
- printf("Unexisting driver RNA path: %s\n", rna_path);
- }
- }
- else if (id_type == ID_KE && strstr(rna_path, "key_blocks[")) {
- /* Shape key driver - hook into the base geometry operation. */
- // XXX: double check where this points
- Key *shape_key = (Key *)id;
- ComponentKey geometry_key(shape_key->from, DEG_NODE_TYPE_GEOMETRY);
- add_relation(driver_key, geometry_key, "[Driver -> ShapeKey Geom]");
- }
- else if (strstr(rna_path, "key_blocks[")) {
- ComponentKey geometry_key(id, DEG_NODE_TYPE_GEOMETRY);
- add_relation(driver_key, geometry_key, "[Driver -> ShapeKey Geom]");
- }
else {
- switch (id_type) {
- case ID_OB:
- {
- /* Assume that driver affects a transform. */
- OperationKey local_transform_key(id,
- DEG_NODE_TYPE_TRANSFORM,
- DEG_OPCODE_TRANSFORM_LOCAL);
- add_relation(driver_key,
- local_transform_key,
- "[Driver -> Transform]");
- break;
- }
- case ID_KE:
- {
- ComponentKey geometry_key(id, DEG_NODE_TYPE_GEOMETRY);
- add_relation(driver_key,
- geometry_key,
- "[Driver -> Shapekey Geometry]");
- break;
- }
- case ID_NT:
- {
- ComponentKey ntree_key(id, DEG_NODE_TYPE_SHADING);
- add_relation(driver_key,
- ntree_key,
- "[Driver -> NTree Shading Update]");
- break;
- }
- default:
- break;
- }
+ RNAPathKey target_key(id, rna_path);
+ add_relation(driver_key, target_key, "Driver -> Target");
}
- /* Ensure that affected prop's update callbacks will be triggered once
- * done.
- */
- /* TODO: Implement this once the functionality to add these links exists
- * RNA.
- */
- /* XXX: the data itself could also set this, if it were to be truly
- * initialised later?
- */
- /* Loop over variables to get the target relationships. */
+}
+
+void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu)
+{
+ ChannelDriver *driver = fcu->driver;
+ OperationKey driver_key(id,
+ DEG_NODE_TYPE_PARAMETERS,
+ DEG_OPCODE_DRIVER,
+ fcu->rna_path ? fcu->rna_path : "",
+ fcu->array_index);
+ const char *rna_path = fcu->rna_path ? fcu->rna_path : "";
+ const RNAPathKey self_key(id, rna_path);
+
LINKLIST_FOREACH (DriverVar *, dvar, &driver->variables) {
/* Only used targets. */
DRIVER_TARGETS_USED_LOOPER(dvar)
@@ -1148,31 +1162,25 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
continue;
}
/* Special handling for directly-named bones. */
- if ((dtar->flag & DTAR_FLAG_STRUCT_REF) && (dtar->pchan_name[0])) {
+ if ((dtar->flag & DTAR_FLAG_STRUCT_REF) &&
+ (((Object *)dtar->id)->type == OB_ARMATURE) &&
+ (dtar->pchan_name[0]))
+ {
Object *object = (Object *)dtar->id;
bPoseChannel *target_pchan =
- BKE_pose_channel_find_name(object->pose, dtar->pchan_name);
- if (target_pchan != NULL) {
- /* Get node associated with bone. */
- // XXX: watch the space!
- /* Some cases can't use final bone transform, for example:
- * - Driving the bone with itself (addressed here)
- * - Relations inside an IK chain (TODO?)
- */
- if (dtar->id == id &&
- pchan != NULL &&
- STREQ(pchan->name, target_pchan->name))
- {
- continue;
- }
- OperationKey target_key(dtar->id,
- DEG_NODE_TYPE_BONE,
- target_pchan->name,
- DEG_OPCODE_BONE_DONE);
- add_relation(target_key,
- driver_key,
- "[Bone Target -> Driver]");
+ BKE_pose_channel_find_name(object->pose,
+ dtar->pchan_name);
+ if (target_pchan == NULL) {
+ continue;
+ }
+ OperationKey variable_key(dtar->id,
+ DEG_NODE_TYPE_BONE,
+ target_pchan->name,
+ DEG_OPCODE_BONE_DONE);
+ if (is_same_bone_dependency(variable_key, self_key)) {
+ continue;
}
+ add_relation(variable_key, driver_key, "Bone Target -> Driver");
}
else if (dtar->flag & DTAR_FLAG_STRUCT_REF) {
/* Get node associated with the object's transforms. */
@@ -1186,34 +1194,17 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
OperationKey target_key(dtar->id,
DEG_NODE_TYPE_TRANSFORM,
DEG_OPCODE_TRANSFORM_FINAL);
- add_relation(target_key, driver_key, "[Target -> Driver]");
+ add_relation(target_key, driver_key, "Target -> Driver");
}
- else if (dtar->rna_path && strstr(dtar->rna_path, "pose.bones[")) {
- /* Workaround for ensuring that local bone transforms don't end
- * up having to wait for pose eval to finish (to prevent cycles).
- */
- Object *object = (Object *)dtar->id;
- char *bone_name = BLI_str_quoted_substrN(dtar->rna_path,
- "pose.bones[");
- bPoseChannel *target_pchan =
- BKE_pose_channel_find_name(object->pose, bone_name);
- if (bone_name != NULL) {
- MEM_freeN(bone_name);
- bone_name = NULL;
+ else if (dtar->rna_path) {
+ RNAPathKey variable_key(dtar->id, dtar->rna_path);
+ if (RNA_pointer_is_null(&variable_key.ptr)) {
+ continue;
}
- if (target_pchan != NULL) {
- if (dtar->id == id &&
- pchan != NULL &&
- STREQ(pchan->name, target_pchan->name))
- {
- continue;
- }
- OperationKey bone_key(dtar->id,
- DEG_NODE_TYPE_BONE,
- target_pchan->name,
- DEG_OPCODE_BONE_LOCAL);
- add_relation(bone_key, driver_key, "[RNA Bone -> Driver]");
+ if (is_same_bone_dependency(variable_key, self_key)) {
+ continue;
}
+ add_relation(variable_key, driver_key, "RNA Bone -> Driver");
}
else {
if (dtar->id == id) {
@@ -1226,21 +1217,11 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
/* Resolve path to get node. */
RNAPathKey target_key(dtar->id,
dtar->rna_path ? dtar->rna_path : "");
- add_relation(target_key, driver_key, "[RNA Target -> Driver]");
+ add_relation(target_key, driver_key, "RNA Target -> Driver");
}
}
DRIVER_TARGETS_LOOPER_END
}
- /* It's quite tricky to detect if the driver actually depends on time or
- * not, so for now we'll be quite conservative here about optimization and
- * consider all python drivers to be depending on time.
- */
- if ((driver->type == DRIVER_TYPE_PYTHON) &&
- python_driver_depends_on_time(driver))
- {
- TimeSourceKey time_src_key;
- add_relation(time_src_key, driver_key, "[TimeSrc -> Driver]");
- }
}
void DepsgraphRelationBuilder::build_world(World *world)
@@ -1285,8 +1266,8 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
/* objects - simulation participants */
if (rbw->group) {
- LINKLIST_FOREACH (GroupObject *, go, &rbw->group->gobject) {
- Object *object = go->ob;
+ LINKLIST_FOREACH (Base *, base, &rbw->group->view_layer->object_bases) {
+ Object *object = base->object;
if (object == NULL || object->type != OB_MESH) {
continue;
}
@@ -1339,8 +1320,8 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
/* constraints */
if (rbw->constraints) {
- LINKLIST_FOREACH (GroupObject *, go, &rbw->constraints->gobject) {
- Object *object = go->ob;
+ LINKLIST_FOREACH (Base *, base, &rbw->constraints->view_layer->object_bases) {
+ Object *object = base->object;
if (object == NULL || !object->rigidbody_constraint) {
continue;
}
@@ -1598,7 +1579,6 @@ void DepsgraphRelationBuilder::build_obdata_geom(Object *object)
if (object->modifiers.first != NULL) {
LINKLIST_FOREACH (ModifierData *, md, &object->modifiers) {
const ModifierTypeInfo *mti = modifierType_getInfo((ModifierType)md->type);
-
if (mti->updateDepsgraph) {
DepsNodeHandle handle = create_node_handle(obdata_ubereval_key);
mti->updateDepsgraph(
@@ -1608,23 +1588,10 @@ void DepsgraphRelationBuilder::build_obdata_geom(Object *object)
object,
reinterpret_cast< ::DepsNodeHandle* >(&handle));
}
-
if (BKE_object_modifier_use_time(object, md)) {
TimeSourceKey time_src_key;
add_relation(time_src_key, obdata_ubereval_key, "Time Source");
-
- /* Hacky fix for T45633 (Animated modifiers aren't updated)
- *
- * This check works because BKE_object_modifier_use_time() tests
- * for either the modifier needing time, or that it is animated.
- */
- /* XXX: Remove this hack when these links are added as part of build_animdata() instead */
- if (modifier_dependsOnTime(md) == false && needs_animdata_node(&object->id)) {
- ComponentKey animation_key(&object->id, DEG_NODE_TYPE_ANIMATION);
- add_relation(animation_key, obdata_ubereval_key, "Modifier Animation");
- }
}
-
if (md->type == eModifierType_Cloth) {
build_cloth(object, md);
}
@@ -1757,16 +1724,6 @@ void DepsgraphRelationBuilder::build_obdata_geom(Object *object)
if (key) {
build_shapekeys(obdata, key);
}
-
- if (needs_animdata_node(obdata)) {
- ComponentKey animation_key(obdata, DEG_NODE_TYPE_ANIMATION);
- ComponentKey parameters_key(obdata, DEG_NODE_TYPE_PARAMETERS);
- add_relation(animation_key, parameters_key, "Geom Parameters");
- /* Evaluation usually depends on animation.
- * TODO(sergey): Need to re-hook it after granular update is implemented..
- */
- add_relation(animation_key, obdata_geom_eval_key, "Animation");
- }
}
/* Cameras */
@@ -1786,11 +1743,6 @@ void DepsgraphRelationBuilder::build_camera(Object *object)
add_relation(camera_parameters_key, object_parameters_key,
"Camera -> Object");
- if (needs_animdata_node(camera_id)) {
- ComponentKey animation_key(camera_id, DEG_NODE_TYPE_ANIMATION);
- add_relation(animation_key, camera_parameters_key, "Camera Parameters");
- }
-
/* DOF */
if (cam->dof_ob != NULL) {
ComponentKey dof_ob_key(&cam->dof_ob->id, DEG_NODE_TYPE_TRANSFORM);
@@ -1814,18 +1766,12 @@ void DepsgraphRelationBuilder::build_lamp(Object *object)
add_relation(lamp_parameters_key, object_parameters_key,
"Lamp -> Object");
- if (needs_animdata_node(lamp_id)) {
- ComponentKey animation_key(lamp_id, DEG_NODE_TYPE_ANIMATION);
- add_relation(animation_key, lamp_parameters_key, "Lamp Parameters");
- }
-
/* lamp's nodetree */
- if (la->nodetree) {
+ if (la->nodetree != NULL) {
build_nodetree(la->nodetree);
ComponentKey nodetree_key(&la->nodetree->id, DEG_NODE_TYPE_SHADING);
add_relation(nodetree_key, lamp_parameters_key, "NTree->Lamp Parameters");
}
-
/* textures */
build_texture_stack(la->mtex);
@@ -1875,6 +1821,9 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
* pipeline. No need to build dependencies for them here.
*/
}
+ else if (id_type == ID_TXT) {
+ /* Ignore script nodes. */
+ }
else if (bnode->type == NODE_GROUP) {
bNodeTree *group_ntree = (bNodeTree *)id;
if ((group_ntree->id.tag & LIB_TAG_DOIT) == 0) {
@@ -1890,11 +1839,6 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
}
}
- if (needs_animdata_node(ntree_id)) {
- ComponentKey animation_key(ntree_id, DEG_NODE_TYPE_ANIMATION);
- add_relation(animation_key, shading_key, "NTree Parameters");
- }
-
OperationKey shading_update_key(ntree_id,
DEG_NODE_TYPE_SHADING,
DEG_OPCODE_MATERIAL_UPDATE);
@@ -1975,15 +1919,6 @@ void DepsgraphRelationBuilder::build_gpencil(bGPdata *gpd)
// TODO: parent object (when that feature is implemented)
}
-bool DepsgraphRelationBuilder::needs_animdata_node(ID *id)
-{
- AnimData *adt = BKE_animdata_from_id(id);
- if (adt != NULL) {
- return (adt->action != NULL) || (adt->nla_tracks.first != NULL);
- }
- return false;
-}
-
void DepsgraphRelationBuilder::build_cachefile(CacheFile *cache_file) {
/* Animation. */
build_animdata(&cache_file->id);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
index 8fe98ae9901..9f661b8e825 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -31,6 +31,7 @@
#pragma once
#include <cstdio>
+#include <cstring>
#include "intern/depsgraph_types.h"
@@ -43,6 +44,7 @@
#include "BLI_string.h"
#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
#include "intern/nodes/deg_node_operation.h"
struct Base;
@@ -175,17 +177,20 @@ struct DepsgraphRelationBuilder
template <typename KeyFrom, typename KeyTo>
void add_relation(const KeyFrom& key_from,
const KeyTo& key_to,
- const char *description);
+ const char *description,
+ bool check_unique = false);
template <typename KeyTo>
void add_relation(const TimeSourceKey& key_from,
const KeyTo& key_to,
- const char *description);
+ const char *description,
+ bool check_unique = false);
template <typename KeyType>
void add_node_handle_relation(const KeyType& key_from,
const DepsNodeHandle *handle,
- const char *description);
+ const char *description,
+ bool check_unique = false);
void build_view_layer(Scene *scene, ViewLayer *view_layer);
void build_group(Object *object, Group *group);
@@ -199,7 +204,12 @@ struct DepsgraphRelationBuilder
ListBase *constraints,
RootPChanMap *root_map);
void build_animdata(ID *id);
+ void build_animdata_curves(ID *id);
+ void build_animdata_curves_targets(ID *id);
+ void build_animdata_drievrs(ID *id);
void build_driver(ID *id, FCurve *fcurve);
+ void build_driver_data(ID *id, FCurve *fcurve);
+ void build_driver_variables(ID *id, FCurve *fcurve);
void build_world(World *world);
void build_rigidbody(Scene *scene);
void build_particles(Object *object);
@@ -249,11 +259,13 @@ struct DepsgraphRelationBuilder
OperationKey done_key;
OperationKey prev_key;
};
- void build_layer_collection(LayerCollection *layer_collection,
+ void build_layer_collection(ID *owner_id,
+ LayerCollection *layer_collection,
LayerCollectionState *state);
- void build_layer_collections(ListBase *layer_collections,
+ void build_layer_collections(ID *owner_id,
+ ListBase *layer_collections,
LayerCollectionState *state);
- void build_view_layer_collections(ViewLayer *view_layer);
+ void build_view_layer_collections(struct ID *owner_id, ViewLayer *view_layer);
void build_copy_on_write_relations();
void build_copy_on_write_relations(IDDepsNode *id_node);
@@ -274,16 +286,19 @@ protected:
void add_time_relation(TimeSourceDepsNode *timesrc,
DepsNode *node_to,
- const char *description);
+ const char *description,
+ bool check_unique = false);
void add_operation_relation(OperationDepsNode *node_from,
OperationDepsNode *node_to,
- const char *description);
+ const char *description,
+ bool check_unique = false);
template <typename KeyType>
DepsNodeHandle create_node_handle(const KeyType& key,
const char *default_name = "");
- bool needs_animdata_node(ID *id);
+ template <typename KeyFrom, typename KeyTo>
+ bool is_same_bone_dependency(const KeyFrom& key_from, const KeyTo& key_to);
private:
/* State which never changes, same for the whole builder time. */
@@ -296,10 +311,12 @@ private:
struct DepsNodeHandle
{
- DepsNodeHandle(DepsgraphRelationBuilder *builder, OperationDepsNode *node, const char *default_name = "") :
- builder(builder),
- node(node),
- default_name(default_name)
+ DepsNodeHandle(DepsgraphRelationBuilder *builder,
+ OperationDepsNode *node,
+ const char *default_name = "")
+ : builder(builder),
+ node(node),
+ default_name(default_name)
{
BLI_assert(node != NULL);
}
@@ -309,92 +326,7 @@ struct DepsNodeHandle
const char *default_name;
};
-/* Utilities for Builders ----------------------------------------------------- */
-
-template <typename KeyType>
-OperationDepsNode *DepsgraphRelationBuilder::find_operation_node(const KeyType& key)
-{
- DepsNode *node = get_node(key);
- return node != NULL ? node->get_exit_operation() : NULL;
-}
-
-template <typename KeyFrom, typename KeyTo>
-void DepsgraphRelationBuilder::add_relation(const KeyFrom &key_from,
- const KeyTo &key_to,
- const char *description)
-{
- DepsNode *node_from = get_node(key_from);
- DepsNode *node_to = get_node(key_to);
- OperationDepsNode *op_from = node_from ? node_from->get_exit_operation() : NULL;
- OperationDepsNode *op_to = node_to ? node_to->get_entry_operation() : NULL;
- if (op_from && op_to) {
- add_operation_relation(op_from, op_to, description);
- }
- else {
- if (!op_from) {
- /* XXX TODO handle as error or report if needed */
- fprintf(stderr, "add_relation(%s) - Could not find op_from (%s)\n",
- description, key_from.identifier().c_str());
- }
- else {
- fprintf(stderr, "add_relation(%s) - Failed, but op_from (%s) was ok\n",
- description, key_from.identifier().c_str());
- }
- if (!op_to) {
- /* XXX TODO handle as error or report if needed */
- fprintf(stderr, "add_relation(%s) - Could not find op_to (%s)\n",
- description, key_to.identifier().c_str());
- }
- else {
- fprintf(stderr, "add_relation(%s) - Failed, but op_to (%s) was ok\n",
- description, key_to.identifier().c_str());
- }
- }
-}
-
-template <typename KeyTo>
-void DepsgraphRelationBuilder::add_relation(const TimeSourceKey &key_from,
- const KeyTo &key_to,
- const char *description)
-{
- TimeSourceDepsNode *time_from = get_node(key_from);
- DepsNode *node_to = get_node(key_to);
- OperationDepsNode *op_to = node_to ? node_to->get_entry_operation() : NULL;
- if (time_from != NULL && op_to != NULL) {
- add_time_relation(time_from, op_to, description);
- }
-}
-
-template <typename KeyType>
-void DepsgraphRelationBuilder::add_node_handle_relation(
- const KeyType &key_from,
- const DepsNodeHandle *handle,
- const char *description)
-{
- DepsNode *node_from = get_node(key_from);
- OperationDepsNode *op_from = node_from ? node_from->get_exit_operation() : NULL;
- OperationDepsNode *op_to = handle->node->get_entry_operation();
- if (op_from != NULL && op_to != NULL) {
- add_operation_relation(op_from, op_to, description);
- }
- else {
- if (!op_from) {
- fprintf(stderr, "add_node_handle_relation(%s) - Could not find op_from (%s)\n",
- description, key_from.identifier().c_str());
- }
- if (!op_to) {
- fprintf(stderr, "add_node_handle_relation(%s) - Could not find op_to (%s)\n",
- description, key_from.identifier().c_str());
- }
- }
-}
+} // namespace DEG
-template <typename KeyType>
-DepsNodeHandle DepsgraphRelationBuilder::create_node_handle(
- const KeyType &key,
- const char *default_name)
-{
- return DepsNodeHandle(this, get_node(key), default_name);
-}
-} // namespace DEG
+#include "intern/builder/deg_builder_relations_impl.h"
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h b/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h
new file mode 100644
index 00000000000..ba55a83b767
--- /dev/null
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h
@@ -0,0 +1,155 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Lukas Toenne
+ * Contributor(s): Sergey SHarybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/builder/deg_builder_relations_impl.h
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+namespace DEG {
+
+template <typename KeyType>
+OperationDepsNode *DepsgraphRelationBuilder::find_operation_node(const KeyType& key)
+{
+ DepsNode *node = get_node(key);
+ return node != NULL ? node->get_exit_operation() : NULL;
+}
+
+template <typename KeyFrom, typename KeyTo>
+void DepsgraphRelationBuilder::add_relation(const KeyFrom &key_from,
+ const KeyTo &key_to,
+ const char *description,
+ bool check_unique)
+{
+ DepsNode *node_from = get_node(key_from);
+ DepsNode *node_to = get_node(key_to);
+ OperationDepsNode *op_from = node_from ? node_from->get_exit_operation() : NULL;
+ OperationDepsNode *op_to = node_to ? node_to->get_entry_operation() : NULL;
+ if (op_from && op_to) {
+ add_operation_relation(op_from, op_to, description, check_unique);
+ }
+ else {
+ if (!op_from) {
+ /* XXX TODO handle as error or report if needed */
+ fprintf(stderr, "add_relation(%s) - Could not find op_from (%s)\n",
+ description, key_from.identifier().c_str());
+ }
+ else {
+ fprintf(stderr, "add_relation(%s) - Failed, but op_from (%s) was ok\n",
+ description, key_from.identifier().c_str());
+ }
+ if (!op_to) {
+ /* XXX TODO handle as error or report if needed */
+ fprintf(stderr, "add_relation(%s) - Could not find op_to (%s)\n",
+ description, key_to.identifier().c_str());
+ }
+ else {
+ fprintf(stderr, "add_relation(%s) - Failed, but op_to (%s) was ok\n",
+ description, key_to.identifier().c_str());
+ }
+ }
+}
+
+template <typename KeyTo>
+void DepsgraphRelationBuilder::add_relation(const TimeSourceKey &key_from,
+ const KeyTo &key_to,
+ const char *description,
+ bool check_unique)
+{
+ TimeSourceDepsNode *time_from = get_node(key_from);
+ DepsNode *node_to = get_node(key_to);
+ OperationDepsNode *op_to = node_to ? node_to->get_entry_operation() : NULL;
+ if (time_from != NULL && op_to != NULL) {
+ add_time_relation(time_from, op_to, description, check_unique);
+ }
+}
+
+template <typename KeyType>
+void DepsgraphRelationBuilder::add_node_handle_relation(
+ const KeyType &key_from,
+ const DepsNodeHandle *handle,
+ const char *description,
+ bool check_unique)
+{
+ DepsNode *node_from = get_node(key_from);
+ OperationDepsNode *op_from = node_from ? node_from->get_exit_operation() : NULL;
+ OperationDepsNode *op_to = handle->node->get_entry_operation();
+ if (op_from != NULL && op_to != NULL) {
+ add_operation_relation(op_from, op_to, description, check_unique);
+ }
+ else {
+ if (!op_from) {
+ fprintf(stderr, "add_node_handle_relation(%s) - Could not find op_from (%s)\n",
+ description, key_from.identifier().c_str());
+ }
+ if (!op_to) {
+ fprintf(stderr, "add_node_handle_relation(%s) - Could not find op_to (%s)\n",
+ description, key_from.identifier().c_str());
+ }
+ }
+}
+
+template <typename KeyType>
+DepsNodeHandle DepsgraphRelationBuilder::create_node_handle(
+ const KeyType &key,
+ const char *default_name)
+{
+ return DepsNodeHandle(this, get_node(key), default_name);
+}
+
+/* Rig compatibility: we check if bone is using local transform as a variable
+ * for driver on itself and ignore those relations to avoid "false-positive"
+ * dependency cycles.
+ */
+template <typename KeyFrom, typename KeyTo>
+bool DepsgraphRelationBuilder::is_same_bone_dependency(const KeyFrom& key_from,
+ const KeyTo& key_to)
+{
+ /* Get operations for requested keys. */
+ DepsNode *node_from = get_node(key_from);
+ DepsNode *node_to = get_node(key_to);
+ if (node_from == NULL || node_to == NULL) {
+ return false;
+ }
+ OperationDepsNode *op_from = node_from->get_exit_operation();
+ OperationDepsNode *op_to = node_to->get_entry_operation();
+ if (op_from == NULL || op_to == NULL) {
+ return false;
+ }
+ /* We are only interested in relations like BONE_DONE -> BONE_LOCAL... */
+ if (!(op_from->opcode == DEG_OPCODE_BONE_DONE &&
+ op_to->opcode == DEG_OPCODE_BONE_LOCAL)) {
+ return false;
+ }
+ /* ... BUT, we also need to check if it's same bone. */
+ if (!STREQ(op_from->owner->name, op_to->owner->name)) {
+ return false;
+ }
+ return true;
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc
index 9d6ab3358a7..4b8e4faae3f 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc
@@ -193,6 +193,20 @@ RNAPathKey::RNAPathKey(ID *id, const PointerRNA &ptr, PropertyRNA *prop)
{
}
+RNAPathKey::RNAPathKey(ID *id, const char *path)
+ : id(id)
+{
+ /* create ID pointer for root of path lookup */
+ PointerRNA id_ptr;
+ RNA_id_pointer_create(id, &id_ptr);
+ /* try to resolve path... */
+ int index;
+ if (!RNA_path_resolve_full(&id_ptr, path, &this->ptr, &this->prop, &index)) {
+ this->ptr = PointerRNA_NULL;
+ this->prop = NULL;
+ }
+}
+
string RNAPathKey::identifier() const
{
const char *id_name = (id) ? id->name : "<No ID>";
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_layer_collection.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_layer_collection.cc
index a7c70bfc098..452bd7b19e7 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_layer_collection.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_layer_collection.cc
@@ -24,7 +24,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/builder/deg_builder_relations_layer.cc
+/** \file blender/depsgraph/intern/builder/deg_builder_relations_layer_collection.cc
* \ingroup depsgraph
*
* Methods for constructing depsgraph
@@ -69,10 +69,11 @@ extern "C" {
namespace DEG {
void DepsgraphRelationBuilder::build_layer_collection(
+ ID *owner_id,
LayerCollection *layer_collection,
LayerCollectionState *state)
{
- OperationKey layer_key(&scene_->id,
+ OperationKey layer_key(owner_id,
DEG_NODE_TYPE_LAYER_COLLECTIONS,
DEG_OPCODE_VIEW_LAYER_EVAL,
layer_collection->scene_collection->name,
@@ -83,29 +84,31 @@ void DepsgraphRelationBuilder::build_layer_collection(
state->prev_key = layer_key;
/* Recurs into nested layer collections. */
- build_layer_collections(&layer_collection->layer_collections, state);
+ build_layer_collections(owner_id, &layer_collection->layer_collections, state);
}
void DepsgraphRelationBuilder::build_layer_collections(
+ ID *owner_id,
ListBase *layer_collections,
LayerCollectionState *state)
{
LINKLIST_FOREACH (LayerCollection *, layer_collection, layer_collections) {
/* Recurs into the layer. */
- build_layer_collection(layer_collection, state);
+ build_layer_collection(owner_id, layer_collection, state);
}
}
void DepsgraphRelationBuilder::build_view_layer_collections(
+ ID *owner_id,
ViewLayer *view_layer)
{
LayerCollectionState state;
state.index = 0;
- OperationKey init_key(&scene_->id,
+ OperationKey init_key(owner_id,
DEG_NODE_TYPE_LAYER_COLLECTIONS,
DEG_OPCODE_VIEW_LAYER_INIT);
- OperationKey done_key(&scene_->id,
+ OperationKey done_key(owner_id,
DEG_NODE_TYPE_LAYER_COLLECTIONS,
DEG_OPCODE_VIEW_LAYER_DONE);
@@ -113,7 +116,7 @@ void DepsgraphRelationBuilder::build_view_layer_collections(
state.done_key = done_key;
state.prev_key = init_key;
- build_layer_collections(&view_layer->layer_collections, &state);
+ build_layer_collections(owner_id, &view_layer->layer_collections, &state);
add_relation(state.prev_key, done_key, "Layer collection order");
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
index ce63d6455cc..2aff1ca33c7 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
@@ -258,7 +258,7 @@ void DepsgraphRelationBuilder::build_splineik_pose(Object *object,
// TODO: the bigggest point here is that we need the curve PATH and not just the general geometry...
ComponentKey target_key(&data->tar->id, DEG_NODE_TYPE_GEOMETRY);
ComponentKey pose_key(&object->id, DEG_NODE_TYPE_EVAL_POSE);
- add_relation(target_key, pose_key, "[Curve.Path -> Spline IK] DepsRel");
+ add_relation(target_key, pose_key, "Curve.Path -> Spline IK");
}
pchan->flag |= POSE_DONE;
@@ -324,11 +324,6 @@ void DepsgraphRelationBuilder::build_rig(Object *object)
"Armature Eval");
add_relation(armature_key, init_key, "Data dependency");
- if (needs_animdata_node(&object->id)) {
- ComponentKey animation_key(&object->id, DEG_NODE_TYPE_ANIMATION);
- add_relation(animation_key, init_key, "Rig Animation");
- }
-
/* IK Solvers...
* - These require separate processing steps are pose-level
* to be executed between chains of bones (i.e. once the
@@ -410,7 +405,7 @@ void DepsgraphRelationBuilder::build_rig(Object *object)
}
OperationKey parent_key(&object->id, DEG_NODE_TYPE_BONE, pchan->parent->name, parent_key_opcode);
- add_relation(parent_key, bone_pose_key, "[Parent Bone -> Child Bone]");
+ add_relation(parent_key, bone_pose_key, "Parent Bone -> Child Bone");
}
/* Buil constraints. */
if (pchan->constraints.first != NULL) {
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc
index d23fdaacf08..29cff0cb28d 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc
@@ -24,7 +24,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/depsgraph/intern/builder/deg_builder_relations_scene.cc
+/** \file blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc
* \ingroup depsgraph
*
* Methods for constructing depsgraph
@@ -72,53 +72,47 @@ void DepsgraphRelationBuilder::build_view_layer(Scene *scene, ViewLayer *view_la
{
/* Setup currently building context. */
scene_ = scene;
-
- /* scene objects */
+ /* Scene objects. */
+ /* NOTE: Nodes builder requires us to pass CoW base because it's being
+ * passed to the evaluation functions. During relations builder we only
+ * do NULL-pointer check of the base, so it's fine to pass original one.
+ */
LINKLIST_FOREACH(Base *, base, &view_layer->object_bases) {
build_object(base, base->object);
}
if (scene->camera != NULL) {
build_object(NULL, scene->camera);
}
-
- /* rigidbody */
- if (scene->rigidbody_world) {
+ /* Rigidbody. */
+ if (scene->rigidbody_world != NULL) {
build_rigidbody(scene);
}
-
- /* scene's animation and drivers */
- if (scene->adt) {
+ /* Scene's animation and drivers. */
+ if (scene->adt != NULL) {
build_animdata(&scene->id);
}
-
- /* world */
- if (scene->world) {
+ /* World. */
+ if (scene->world != NULL) {
build_world(scene->world);
}
-
- /* compo nodes */
- if (scene->nodetree) {
+ /* Compositor nodes. */
+ if (scene->nodetree != NULL) {
build_compositor(scene);
}
-
- /* grease pencil */
- if (scene->gpd) {
+ /* Grease pencil. */
+ if (scene->gpd != NULL) {
build_gpencil(scene->gpd);
}
-
/* Masks. */
LINKLIST_FOREACH (Mask *, mask, &bmain_->mask) {
build_mask(mask);
}
-
/* Movie clips. */
LINKLIST_FOREACH (MovieClip *, clip, &bmain_->movieclip) {
build_movieclip(clip);
}
-
/* Collections. */
- build_view_layer_collections(view_layer);
-
+ build_view_layer_collections(&scene_->id, view_layer);
/* TODO(sergey): Do this flush on CoW object? */
foreach (OperationDepsNode *node, graph_->operations) {
IDDepsNode *id_node = node->owner->owner;
@@ -128,7 +122,6 @@ void DepsgraphRelationBuilder::build_view_layer(Scene *scene, ViewLayer *view_la
object->customdata_mask |= node->customdata_mask;
}
}
-
/* Build all set scenes. */
if (scene->set != NULL) {
ViewLayer *set_view_layer = BKE_view_layer_from_scene_get(scene->set);
diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc
index d4907eeff46..4fea8b49706 100644
--- a/source/blender/depsgraph/intern/depsgraph.cc
+++ b/source/blender/depsgraph/intern/depsgraph.cc
@@ -78,7 +78,6 @@ namespace DEG {
static DEG_EditorUpdateIDCb deg_editor_update_id_cb = NULL;
static DEG_EditorUpdateSceneCb deg_editor_update_scene_cb = NULL;
-static DEG_EditorUpdateScenePreCb deg_editor_update_scene_pre_cb = NULL;
Depsgraph::Depsgraph()
: time_source(NULL),
@@ -104,72 +103,60 @@ Depsgraph::~Depsgraph()
/* Query Conditions from RNA ----------------------- */
-static bool pointer_to_id_node_criteria(const PointerRNA *ptr,
- const PropertyRNA *prop,
- ID **id)
+static bool pointer_to_component_node_criteria(
+ const PointerRNA *ptr,
+ const PropertyRNA *prop,
+ ID **id,
+ eDepsNode_Type *type,
+ const char **subdata,
+ eDepsOperation_Code *operation_code,
+ const char **operation_name,
+ int *operation_name_tag)
{
- if (!ptr->type)
+ if (ptr->type == NULL) {
return false;
-
- if (!prop) {
- if (RNA_struct_is_ID(ptr->type)) {
- *id = (ID *)ptr->data;
- return true;
- }
}
-
- return false;
-}
-
-static bool pointer_to_component_node_criteria(const PointerRNA *ptr,
- const PropertyRNA *prop,
- ID **id,
- eDepsNode_Type *type,
- const char **subdata)
-{
- if (!ptr->type)
- return false;
-
/* Set default values for returns. */
- *id = (ID *)ptr->id.data; /* For obvious reasons... */
- *subdata = ""; /* Default to no subdata (e.g. bone) name
- * lookup in most cases. */
-
- /* Handling of commonly known scenarios... */
+ *id = (ID *)ptr->id.data;
+ *subdata = "";
+ *operation_code = DEG_OPCODE_OPERATION;
+ *operation_name = "";
+ *operation_name_tag = -1;
+ /* Handling of commonly known scenarios. */
if (ptr->type == &RNA_PoseBone) {
bPoseChannel *pchan = (bPoseChannel *)ptr->data;
-
- /* Bone - generally, we just want the bone component... */
- *type = DEG_NODE_TYPE_BONE;
- *subdata = pchan->name;
-
+ if (prop != NULL && RNA_property_is_idprop(prop)) {
+ *type = DEG_NODE_TYPE_PARAMETERS;
+ *subdata = "";
+ *operation_code = DEG_OPCODE_PARAMETERS_EVAL;
+ *operation_name = pchan->name;;
+ }
+ else {
+ /* Bone - generally, we just want the bone component. */
+ *type = DEG_NODE_TYPE_BONE;
+ *subdata = pchan->name;
+ }
return true;
}
else if (ptr->type == &RNA_Bone) {
Bone *bone = (Bone *)ptr->data;
-
/* armature-level bone, but it ends up going to bone component anyway */
- // TODO: the ID in thise case will end up being bArmature, not Object as needed!
+ // NOTE: the ID in thise case will end up being bArmature.
*type = DEG_NODE_TYPE_BONE;
*subdata = bone->name;
- //*id = ...
-
return true;
}
else if (RNA_struct_is_a(ptr->type, &RNA_Constraint)) {
Object *object = (Object *)ptr->id.data;
bConstraint *con = (bConstraint *)ptr->data;
-
- /* object or bone? */
+ /* Check whether is object or bone constraint. */
if (BLI_findindex(&object->constraints, con) != -1) {
- /* object transform */
- // XXX: for now, we can't address the specific constraint or the constraint stack...
+ /* Constraint is defining object transform. */
*type = DEG_NODE_TYPE_TRANSFORM;
return true;
}
- else if (object->pose) {
- bPoseChannel *pchan;
- for (pchan = (bPoseChannel *)object->pose->chanbase.first; pchan; pchan = pchan->next) {
+ else if (object->pose != NULL) {
+ LINKLIST_FOREACH(bPoseChannel *, pchan, &object->pose->chanbase) {
if (BLI_findindex(&pchan->constraints, con) != -1) {
/* bone transforms */
*type = DEG_NODE_TYPE_BONE;
@@ -180,23 +167,12 @@ static bool pointer_to_component_node_criteria(const PointerRNA *ptr,
}
}
else if (RNA_struct_is_a(ptr->type, &RNA_Modifier)) {
- //ModifierData *md = (ModifierData *)ptr->data;
-
- /* Modifier */
- /* NOTE: subdata is not the same as "operation name",
- * so although we have unique ops for modifiers,
- * we can't lump them together
- */
- *type = DEG_NODE_TYPE_BONE;
- //*subdata = md->name;
-
+ *type = DEG_NODE_TYPE_GEOMETRY;
return true;
}
else if (ptr->type == &RNA_Object) {
- //Object *object = (Object *)ptr->data;
-
/* Transforms props? */
- if (prop) {
+ if (prop != NULL) {
const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop);
/* TODO(sergey): How to optimize this? */
if (strstr(prop_identifier, "location") ||
@@ -218,11 +194,16 @@ static bool pointer_to_component_node_criteria(const PointerRNA *ptr,
}
else if (ptr->type == &RNA_ShapeKey) {
Key *key = (Key *)ptr->id.data;
-
- /* ShapeKeys are currently handled as geometry on the geometry that owns it */
- *id = key->from; // XXX
- *type = DEG_NODE_TYPE_PARAMETERS;
-
+ /* ShapeKeys are currently handled as geometry on the geometry that
+ * owns it.
+ */
+ *id = key->from;
+ *type = DEG_NODE_TYPE_GEOMETRY;
+ return true;
+ }
+ else if (ptr->type == &RNA_Key) {
+ *id = (ID *)ptr->id.data;
+ *type = DEG_NODE_TYPE_GEOMETRY;
return true;
}
else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) {
@@ -232,13 +213,14 @@ static bool pointer_to_component_node_criteria(const PointerRNA *ptr,
*subdata = seq->name; // xxx?
return true;
}
-
- if (prop) {
- /* All unknown data effectively falls under "parameter evaluation" */
+ if (prop != NULL) {
+ /* All unknown data effectively falls under "parameter evaluation". */
*type = DEG_NODE_TYPE_PARAMETERS;
+ *operation_code = DEG_OPCODE_PARAMETERS_EVAL;
+ *operation_name = "";
+ *operation_name_tag = -1;
return true;
}
-
return false;
}
@@ -247,20 +229,32 @@ DepsNode *Depsgraph::find_node_from_pointer(const PointerRNA *ptr,
const PropertyRNA *prop) const
{
ID *id;
- eDepsNode_Type type;
- const char *name;
-
- /* Get querying conditions. */
- if (pointer_to_id_node_criteria(ptr, prop, &id)) {
- return find_id_node(id);
- }
- else if (pointer_to_component_node_criteria(ptr, prop, &id, &type, &name)) {
+ eDepsNode_Type node_type;
+ const char *component_name, *operation_name;
+ eDepsOperation_Code operation_code;
+ int operation_name_tag;
+
+ if (pointer_to_component_node_criteria(
+ ptr, prop,
+ &id, &node_type, &component_name,
+ &operation_code, &operation_name, &operation_name_tag))
+ {
IDDepsNode *id_node = find_id_node(id);
- if (id_node != NULL) {
- return id_node->find_component(type, name);
+ if (id_node == NULL) {
+ return NULL;
+ }
+ ComponentDepsNode *comp_node =
+ id_node->find_component(node_type, component_name);
+ if (comp_node == NULL) {
+ return NULL;
}
+ if (operation_code == DEG_OPCODE_OPERATION) {
+ return comp_node;
+ }
+ return comp_node->find_operation(operation_code,
+ operation_name,
+ operation_name_tag);
}
-
return NULL;
}
@@ -342,10 +336,18 @@ void Depsgraph::clear_id_nodes()
/* Add new relationship between two nodes. */
DepsRelation *Depsgraph::add_new_relation(OperationDepsNode *from,
OperationDepsNode *to,
- const char *description)
+ const char *description,
+ bool check_unique)
{
+ DepsRelation *rel = NULL;
+ if (check_unique) {
+ rel = check_nodes_connected(from, to, description);
+ }
+ if (rel != NULL) {
+ return rel;
+ }
/* Create new relation, and add it to the graph. */
- DepsRelation *rel = OBJECT_GUARDED_NEW(DepsRelation, from, to, description);
+ rel = OBJECT_GUARDED_NEW(DepsRelation, from, to, description);
/* TODO(sergey): Find a better place for this. */
#ifdef WITH_OPENSUBDIV
ComponentDepsNode *comp_node = from->owner;
@@ -365,13 +367,38 @@ DepsRelation *Depsgraph::add_new_relation(OperationDepsNode *from,
/* Add new relation between two nodes */
DepsRelation *Depsgraph::add_new_relation(DepsNode *from, DepsNode *to,
- const char *description)
+ const char *description,
+ bool check_unique)
{
+ DepsRelation *rel = NULL;
+ if (check_unique) {
+ rel = check_nodes_connected(from, to, description);
+ }
+ if (rel != NULL) {
+ return rel;
+ }
/* Create new relation, and add it to the graph. */
- DepsRelation *rel = OBJECT_GUARDED_NEW(DepsRelation, from, to, description);
+ rel = OBJECT_GUARDED_NEW(DepsRelation, from, to, description);
return rel;
}
+DepsRelation *Depsgraph::check_nodes_connected(const DepsNode *from,
+ const DepsNode *to,
+ const char *description)
+{
+ foreach (DepsRelation *rel, from->outlinks) {
+ BLI_assert(rel->from == from);
+ if (rel->to != to) {
+ continue;
+ }
+ if (description != NULL && !STREQ(rel->name, description)) {
+ continue;
+ }
+ return rel;
+ }
+ return NULL;
+}
+
/* ************************ */
/* Relationships Management */
@@ -383,24 +410,6 @@ DepsRelation::DepsRelation(DepsNode *from,
name(description),
flag(0)
{
-#ifndef NDEBUG
-/*
- for (OperationDepsNode::Relations::const_iterator it = from->outlinks.begin();
- it != from->outlinks.end();
- ++it)
- {
- DepsRelation *rel = *it;
- if (rel->from == from &&
- rel->to == to &&
- rel->type == type &&
- rel->name == description)
- {
- BLI_assert(!"Duplicated relation, should not happen!");
- }
- }
-*/
-#endif
-
/* Hook it up to the nodes which use it.
*
* NOTE: We register relation in the nodes which this link connects to here
@@ -477,17 +486,18 @@ ID *Depsgraph::get_cow_id(const ID *id_orig) const
return id_node->id_cow;
}
-void deg_editors_id_update(Main *bmain, ID *id)
+void deg_editors_id_update(const DEGEditorUpdateContext *update_ctx, ID *id)
{
if (deg_editor_update_id_cb != NULL) {
- deg_editor_update_id_cb(bmain, id);
+ deg_editor_update_id_cb(update_ctx, id);
}
}
-void deg_editors_scene_update(Main *bmain, Scene *scene, bool updated)
+void deg_editors_scene_update(const DEGEditorUpdateContext *update_ctx,
+ bool updated)
{
if (deg_editor_update_scene_cb != NULL) {
- deg_editor_update_scene_cb(bmain, scene, updated);
+ deg_editor_update_scene_cb(update_ctx, updated);
}
}
@@ -513,17 +523,8 @@ void DEG_graph_free(Depsgraph *graph)
/* Set callbacks which are being called when depsgraph changes. */
void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func,
- DEG_EditorUpdateSceneCb scene_func,
- DEG_EditorUpdateScenePreCb scene_pre_func)
+ DEG_EditorUpdateSceneCb scene_func)
{
DEG::deg_editor_update_id_cb = id_func;
DEG::deg_editor_update_scene_cb = scene_func;
- DEG::deg_editor_update_scene_pre_cb = scene_pre_func;
-}
-
-void DEG_editors_update_pre(Main *bmain, Scene *scene, bool time)
-{
- if (DEG::deg_editor_update_scene_pre_cb != NULL) {
- DEG::deg_editor_update_scene_pre_cb(bmain, scene, time);
- }
}
diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h
index d841ae045f2..8a34be0c7a2 100644
--- a/source/blender/depsgraph/intern/depsgraph.h
+++ b/source/blender/depsgraph/intern/depsgraph.h
@@ -123,11 +123,21 @@ struct Depsgraph {
/* Add new relationship between two nodes. */
DepsRelation *add_new_relation(OperationDepsNode *from,
OperationDepsNode *to,
- const char *description);
+ const char *description,
+ bool check_unique = false);
DepsRelation *add_new_relation(DepsNode *from,
DepsNode *to,
- const char *description);
+ const char *description,
+ bool check_unique = false);
+
+ /* Check whether two nodes are connected by relation with given
+ * description. Description might be NULL to check ANY relation between
+ * given nodes.
+ */
+ DepsRelation *check_nodes_connected(const DepsNode *from,
+ const DepsNode *to,
+ const char *description);
/* Tag a specific node as needing updates. */
void add_entry_tag(OperationDepsNode *node);
diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc
index 68cf4d77360..57153279acb 100644
--- a/source/blender/depsgraph/intern/depsgraph_build.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build.cc
@@ -206,6 +206,7 @@ void DEG_graph_build_from_view_layer(Depsgraph *graph,
#endif
DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(graph);
+ BLI_assert(BLI_findindex(&scene->view_layers, view_layer) != -1);
/* TODO(sergey): This is a bit tricky, but ensures that all the data
* is evaluated properly when depsgraph is becoming "visible".
diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc
index 31332b416d5..1d389b902b8 100644
--- a/source/blender/depsgraph/intern/depsgraph_eval.cc
+++ b/source/blender/depsgraph/intern/depsgraph_eval.cc
@@ -81,13 +81,13 @@ void DEG_evaluation_context_init(EvaluationContext *eval_ctx,
void DEG_evaluation_context_init_from_scene(EvaluationContext *eval_ctx,
Scene *scene,
ViewLayer *view_layer,
- RenderEngineType *engine,
+ RenderEngineType *engine_type,
eEvaluationMode mode)
{
DEG_evaluation_context_init(eval_ctx, mode);
eval_ctx->depsgraph = BKE_scene_get_depsgraph(scene, view_layer, false);
eval_ctx->view_layer = view_layer;
- eval_ctx->engine = engine;
+ eval_ctx->engine_type = engine_type;
eval_ctx->ctime = BKE_scene_frame_get(scene);
BLI_assert(eval_ctx->depsgraph != NULL);
}
diff --git a/source/blender/depsgraph/intern/depsgraph_intern.h b/source/blender/depsgraph/intern/depsgraph_intern.h
index 5ab090f3b3d..e7e472ea5d6 100644
--- a/source/blender/depsgraph/intern/depsgraph_intern.h
+++ b/source/blender/depsgraph/intern/depsgraph_intern.h
@@ -46,8 +46,9 @@ extern "C" {
#include "intern/nodes/deg_node_operation.h"
#include "intern/depsgraph.h"
-struct Main;
+struct DEGEditorUpdateContext;
struct Group;
+struct Main;
struct Scene;
namespace DEG {
@@ -109,9 +110,11 @@ DepsNodeFactory *deg_node_get_factory(const DepsNode *node);
/* Editors Integration -------------------------------------------------- */
-void deg_editors_id_update(struct Main *bmain, struct ID *id);
+void deg_editors_id_update(const DEGEditorUpdateContext *update_ctx,
+ struct ID *id);
-void deg_editors_scene_update(struct Main *bmain, struct Scene *scene, bool updated);
+void deg_editors_scene_update(const DEGEditorUpdateContext *update_ctx,
+ bool updated);
/* Tagging helpers ------------------------------------------------------ */
diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc
index f2288e93beb..6892bdaa178 100644
--- a/source/blender/depsgraph/intern/depsgraph_query.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query.cc
@@ -34,11 +34,7 @@
extern "C" {
#include "BLI_utildefines.h"
-#include "BLI_ghash.h"
-#include "BLI_math.h"
-#include "BKE_anim.h"
#include "BKE_idcode.h"
-#include "BKE_layer.h"
#include "BKE_main.h"
#include "BLI_listbase.h"
} /* extern "C" */
@@ -50,11 +46,6 @@ extern "C" {
#include "DEG_depsgraph_query.h"
#include "intern/depsgraph_intern.h"
-#include "util/deg_util_foreach.h"
-
-#ifndef NDEBUG
-# include "intern/eval/deg_eval_copy_on_write.h"
-#endif
bool DEG_id_type_tagged(Main *bmain, short id_type)
{
@@ -122,159 +113,3 @@ ID *DEG_get_evaluated_id(struct Depsgraph *depsgraph, ID *id)
return id_node->id_cow;
}
-/* ************************ DEG ITERATORS ********************* */
-
-static bool deg_objects_dupli_iterator_next(BLI_Iterator *iter)
-{
- DEGObjectsIteratorData *data = (DEGObjectsIteratorData *)iter->data;
- while (data->dupli_object_next != NULL) {
- DupliObject *dob = data->dupli_object_next;
- Object *obd = dob->ob;
-
- data->dupli_object_next = data->dupli_object_next->next;
-
- /* Group duplis need to set ob matrices correct, for deform. so no_draw
- * is part handled.
- */
- if ((obd->transflag & OB_RENDER_DUPLI) == 0 && dob->no_draw) {
- continue;
- }
-
- if (obd->type == OB_MBALL) {
- continue;
- }
-
- data->dupli_object_current = dob;
-
- /* Temporary object to evaluate. */
- Object *dupli_parent = data->dupli_parent;
- Object *temp_dupli_object = &data->temp_dupli_object;
- *temp_dupli_object = *dob->ob;
- temp_dupli_object->select_color = dupli_parent->select_color;
- temp_dupli_object->base_flag = dupli_parent->base_flag | BASE_FROMDUPLI;
- temp_dupli_object->base_collection_properties =
- dupli_parent->base_collection_properties;
- copy_m4_m4(data->temp_dupli_object.obmat, dob->mat);
-
- iter->current = &data->temp_dupli_object;
- BLI_assert(
- DEG::deg_validate_copy_on_write_datablock(
- &data->temp_dupli_object.id));
- return true;
- }
-
- return false;
-}
-
-static void deg_objects_iterator_step(BLI_Iterator *iter, DEG::IDDepsNode *id_node)
-{
- /* Reset the skip in case we are running from within a loop. */
- iter->skip = false;
-
- DEGObjectsIteratorData *data = (DEGObjectsIteratorData *)iter->data;
- const ID_Type id_type = GS(id_node->id_orig->name);
-
- if (id_type != ID_OB) {
- iter->skip = true;
- return;
- }
-
- switch (id_node->linked_state) {
- case DEG::DEG_ID_LINKED_DIRECTLY:
- break;
- case DEG::DEG_ID_LINKED_VIA_SET:
- if (data->flag & DEG_OBJECT_ITER_FLAG_SET) {
- break;
- }
- else {
- ATTR_FALLTHROUGH;
- }
- case DEG::DEG_ID_LINKED_INDIRECTLY:
- iter->skip = true;
- return;
- }
-
- Object *object = (Object *)id_node->id_cow;
- BLI_assert(DEG::deg_validate_copy_on_write_datablock(&object->id));
-
- if ((data->flag & DEG_OBJECT_ITER_FLAG_DUPLI) && (object->transflag & OB_DUPLI)) {
- data->dupli_parent = object;
- data->dupli_list = object_duplilist(&data->eval_ctx, data->scene, object);
- data->dupli_object_next = (DupliObject *)data->dupli_list->first;
- }
-
- iter->current = object;
-}
-
-void DEG_objects_iterator_begin(BLI_Iterator *iter, DEGObjectsIteratorData *data)
-{
- Depsgraph *depsgraph = data->graph;
- DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph);
- const size_t num_id_nodes = deg_graph->id_nodes.size();
-
- if (num_id_nodes == 0) {
- iter->valid = false;
- return;
- }
-
- /* TODO(sergey): What evaluation type we want here? */
- DEG_evaluation_context_init(&data->eval_ctx, DAG_EVAL_RENDER);
- data->eval_ctx.view_layer = DEG_get_evaluated_view_layer(depsgraph);
-
- iter->data = data;
- data->dupli_parent = NULL;
- data->dupli_list = NULL;
- data->dupli_object_next = NULL;
- data->dupli_object_current = NULL;
- data->scene = DEG_get_evaluated_scene(depsgraph);
- data->id_node_index = 0;
- data->num_id_nodes = num_id_nodes;
-
- DEG::IDDepsNode *id_node = deg_graph->id_nodes[data->id_node_index];
- deg_objects_iterator_step(iter, id_node);
-
- if (iter->skip) {
- DEG_objects_iterator_next(iter);
- }
-}
-
-void DEG_objects_iterator_next(BLI_Iterator *iter)
-{
- DEGObjectsIteratorData *data = (DEGObjectsIteratorData *)iter->data;
- Depsgraph *depsgraph = data->graph;
- DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph);
- do {
- if (data->dupli_list) {
- if (deg_objects_dupli_iterator_next(iter)) {
- return;
- }
- else {
- free_object_duplilist(data->dupli_list);
- data->dupli_parent = NULL;
- data->dupli_list = NULL;
- data->dupli_object_next = NULL;
- data->dupli_object_current = NULL;
- }
- }
-
- ++data->id_node_index;
- if (data->id_node_index == data->num_id_nodes) {
- iter->valid = false;
- return;
- }
-
- DEG::IDDepsNode *id_node = deg_graph->id_nodes[data->id_node_index];
- deg_objects_iterator_step(iter, id_node);
- } while (iter->skip);
-}
-
-void DEG_objects_iterator_end(BLI_Iterator *iter)
-{
-#ifndef NDEBUG
- DEGObjectsIteratorData *data = (DEGObjectsIteratorData *)iter->data;
- /* Force crash in case the iterator data is referenced and accessed down the line. (T51718) */
- memset(&data->temp_dupli_object, 0xff, sizeof(data->temp_dupli_object));
-#else
- (void) iter;
-#endif
-}
diff --git a/source/blender/depsgraph/intern/depsgraph_query_foreach.cc b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
new file mode 100644
index 00000000000..b1353f528bc
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
@@ -0,0 +1,147 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Sergey Sharybin
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_query_foreach.cc
+ * \ingroup depsgraph
+ *
+ * Implementation of Querying and Filtering API's
+ */
+
+// TODO(sergey): Use some sort of wrapper.
+#include <deque>
+
+#include "MEM_guardedalloc.h"
+
+extern "C" {
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+} /* extern "C" */
+
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "intern/depsgraph_intern.h"
+
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+
+#include "util/deg_util_foreach.h"
+
+/* ************************ DEG TRAVERSAL ********************* */
+
+namespace DEG {
+
+typedef std::deque<OperationDepsNode *> TraversalQueue;
+
+static void deg_foreach_clear_flags(const Depsgraph *graph)
+{
+ foreach (OperationDepsNode *op_node, graph->operations) {
+ op_node->scheduled = false;
+ }
+ foreach (IDDepsNode *id_node, graph->id_nodes) {
+ id_node->done = false;
+ }
+}
+
+static void deg_foreach_dependent_ID(const Depsgraph *graph,
+ const ID *id,
+ DEGForeachIDCallback callback,
+ void *user_data)
+{
+ /* Start with getting ID node from the graph. */
+ IDDepsNode *id_node = graph->find_id_node(id);
+ if (id_node == NULL) {
+ /* TODO(sergey): Shall we inform or assert here about attempt to start
+ * iterating over non-existing ID?
+ */
+ return;
+ }
+ /* Make sure all runtime flags are ready and clear. */
+ deg_foreach_clear_flags(graph);
+ /* Start with scheduling all operations from ID node. */
+ TraversalQueue queue;
+ GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, id_node->components)
+ {
+ foreach (OperationDepsNode *op_node, comp_node->operations) {
+ queue.push_back(op_node);
+ op_node->scheduled = true;
+ }
+ }
+ GHASH_FOREACH_END();
+ id_node->done = true;
+ /* Process the queue. */
+ while (!queue.empty()) {
+ /* get next operation node to process. */
+ OperationDepsNode *op_node = queue.front();
+ queue.pop_front();
+ for (;;) {
+ /* Check whether we need to inform callee about corresponding ID node. */
+ ComponentDepsNode *comp_node = op_node->owner;
+ IDDepsNode *id_node = comp_node->owner;
+ if (!id_node->done) {
+ /* TODO(sergey): Is it orig or CoW? */
+ callback(id_node->id_orig, user_data);
+ id_node->done = true;
+ }
+ /* Schedule outgoing operation nodes. */
+ if (op_node->outlinks.size() == 1) {
+ OperationDepsNode *to_node = (OperationDepsNode *)op_node->outlinks[0]->to;
+ if (to_node->scheduled == false) {
+ to_node->scheduled = true;
+ op_node = to_node;
+ }
+ else {
+ break;
+ }
+ }
+ else {
+ foreach (DepsRelation *rel, op_node->outlinks) {
+ OperationDepsNode *to_node = (OperationDepsNode *)rel->to;
+ if (to_node->scheduled == false) {
+ queue.push_front(to_node);
+ to_node->scheduled = true;
+ }
+ }
+ break;
+ }
+ }
+ }
+}
+
+} // namespace DEG
+
+void DEG_foreach_dependent_ID(const Depsgraph *depsgraph,
+ const ID *id,
+ DEGForeachIDCallback callback, void *user_data)
+{
+ DEG::deg_foreach_dependent_ID((const DEG::Depsgraph *)depsgraph,
+ id,
+ callback, user_data);
+}
diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc
new file mode 100644
index 00000000000..d8a54642a85
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc
@@ -0,0 +1,211 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Dalai Felinto
+ * Contributor(s): Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/depsgraph_query_iter.cc
+ * \ingroup depsgraph
+ *
+ * Implementation of Querying and Filtering API's
+ */
+
+#include "MEM_guardedalloc.h"
+
+extern "C" {
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+#include "BKE_anim.h"
+#include "BKE_idprop.h"
+#include "BKE_layer.h"
+} /* extern "C" */
+
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "intern/depsgraph_intern.h"
+#include "util/deg_util_foreach.h"
+
+#ifndef NDEBUG
+# include "intern/eval/deg_eval_copy_on_write.h"
+#endif
+
+/* ************************ DEG ITERATORS ********************* */
+
+static bool deg_objects_dupli_iterator_next(BLI_Iterator *iter)
+{
+ DEGOIterObjectData *data = (DEGOIterObjectData *)iter->data;
+ while (data->dupli_object_next != NULL) {
+ DupliObject *dob = data->dupli_object_next;
+ Object *obd = dob->ob;
+
+ data->dupli_object_next = data->dupli_object_next->next;
+
+ /* Group duplis need to set ob matrices correct, for deform. so no_draw
+ * is part handled.
+ */
+ if ((obd->transflag & OB_RENDER_DUPLI) == 0 && dob->no_draw) {
+ continue;
+ }
+
+ if (obd->type == OB_MBALL) {
+ continue;
+ }
+
+ data->dupli_object_current = dob;
+
+ /* Temporary object to evaluate. */
+ Object *dupli_parent = data->dupli_parent;
+ Object *temp_dupli_object = &data->temp_dupli_object;
+ *temp_dupli_object = *dob->ob;
+ temp_dupli_object->select_color = dupli_parent->select_color;
+ temp_dupli_object->base_flag = dupli_parent->base_flag | BASE_FROMDUPLI;
+ BLI_assert(dob->collection_properties != NULL);
+ temp_dupli_object->base_collection_properties = dob->collection_properties;
+ IDP_MergeGroup(temp_dupli_object->base_collection_properties, dupli_parent->base_collection_properties, false);
+ copy_m4_m4(data->temp_dupli_object.obmat, dob->mat);
+ iter->current = &data->temp_dupli_object;
+ BLI_assert(
+ DEG::deg_validate_copy_on_write_datablock(
+ &data->temp_dupli_object.id));
+ return true;
+ }
+
+ return false;
+}
+
+static void DEG_iterator_objects_step(BLI_Iterator *iter, DEG::IDDepsNode *id_node)
+{
+ /* Reset the skip in case we are running from within a loop. */
+ iter->skip = false;
+
+ DEGOIterObjectData *data = (DEGOIterObjectData *)iter->data;
+ const ID_Type id_type = GS(id_node->id_orig->name);
+
+ if (id_type != ID_OB) {
+ iter->skip = true;
+ return;
+ }
+
+ switch (id_node->linked_state) {
+ case DEG::DEG_ID_LINKED_DIRECTLY:
+ break;
+ case DEG::DEG_ID_LINKED_VIA_SET:
+ if (data->flag & DEG_ITER_OBJECT_FLAG_SET) {
+ break;
+ }
+ else {
+ ATTR_FALLTHROUGH;
+ }
+ case DEG::DEG_ID_LINKED_INDIRECTLY:
+ iter->skip = true;
+ return;
+ }
+
+ Object *object = (Object *)id_node->id_cow;
+ BLI_assert(DEG::deg_validate_copy_on_write_datablock(&object->id));
+
+ if ((data->flag & DEG_ITER_OBJECT_FLAG_DUPLI) && (object->transflag & OB_DUPLI)) {
+ data->dupli_parent = object;
+ data->dupli_list = object_duplilist(&data->eval_ctx, data->scene, object);
+ data->dupli_object_next = (DupliObject *)data->dupli_list->first;
+ }
+
+ iter->current = object;
+}
+
+void DEG_iterator_objects_begin(BLI_Iterator *iter, DEGOIterObjectData *data)
+{
+ Depsgraph *depsgraph = data->graph;
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph);
+ const size_t num_id_nodes = deg_graph->id_nodes.size();
+
+ if (num_id_nodes == 0) {
+ iter->valid = false;
+ return;
+ }
+
+ /* TODO(sergey): What evaluation type we want here? */
+ DEG_evaluation_context_init(&data->eval_ctx, DAG_EVAL_RENDER);
+ data->eval_ctx.view_layer = DEG_get_evaluated_view_layer(depsgraph);
+
+ iter->data = data;
+ data->dupli_parent = NULL;
+ data->dupli_list = NULL;
+ data->dupli_object_next = NULL;
+ data->dupli_object_current = NULL;
+ data->scene = DEG_get_evaluated_scene(depsgraph);
+ data->id_node_index = 0;
+ data->num_id_nodes = num_id_nodes;
+
+ DEG::IDDepsNode *id_node = deg_graph->id_nodes[data->id_node_index];
+ DEG_iterator_objects_step(iter, id_node);
+
+ if (iter->skip) {
+ DEG_iterator_objects_next(iter);
+ }
+}
+
+void DEG_iterator_objects_next(BLI_Iterator *iter)
+{
+ DEGOIterObjectData *data = (DEGOIterObjectData *)iter->data;
+ Depsgraph *depsgraph = data->graph;
+ DEG::Depsgraph *deg_graph = reinterpret_cast<DEG::Depsgraph *>(depsgraph);
+ do {
+ if (data->dupli_list) {
+ if (deg_objects_dupli_iterator_next(iter)) {
+ return;
+ }
+ else {
+ free_object_duplilist(data->dupli_list);
+ data->dupli_parent = NULL;
+ data->dupli_list = NULL;
+ data->dupli_object_next = NULL;
+ data->dupli_object_current = NULL;
+ }
+ }
+
+ ++data->id_node_index;
+ if (data->id_node_index == data->num_id_nodes) {
+ iter->valid = false;
+ return;
+ }
+
+ DEG::IDDepsNode *id_node = deg_graph->id_nodes[data->id_node_index];
+ DEG_iterator_objects_step(iter, id_node);
+ } while (iter->skip);
+}
+
+void DEG_iterator_objects_end(BLI_Iterator *iter)
+{
+#ifndef NDEBUG
+ DEGOIterObjectData *data = (DEGOIterObjectData *)iter->data;
+ /* Force crash in case the iterator data is referenced and accessed down the line. (T51718) */
+ memset(&data->temp_dupli_object, 0xff, sizeof(data->temp_dupli_object));
+#else
+ (void) iter;
+#endif
+}
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
index faaf3a828b2..e928da58e87 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -111,11 +111,6 @@ void lib_id_recalc_tag_flag(Main *bmain, ID *id, int flag)
* after relations update and after layer visibility changes.
*/
if (flag) {
- ID_Type id_type = GS(id->name);
- if (id_type == ID_OB) {
- Object *object = (Object *)id;
- object->recalc |= (flag & OB_RECALC_ALL);
- }
if (flag & OB_RECALC_OB) {
lib_id_recalc_tag(bmain, id);
}
@@ -352,6 +347,19 @@ void id_tag_update_base_flags(Depsgraph *graph, IDDepsNode *id_node)
}
}
+void id_tag_update_editors_update(Main *bmain, Depsgraph *graph, ID *id)
+{
+ /* NOTE: We handle this immediately, without delaying anything, to be
+ * sure we don't cause threading issues with OpenGL.
+ */
+ /* TODO(sergey): Make sure this works for CoW-ed datablocks as well. */
+ DEGEditorUpdateContext update_ctx = {NULL};
+ update_ctx.bmain = bmain;
+ update_ctx.scene = graph->scene;
+ update_ctx.view_layer = graph->view_layer;
+ deg_editors_id_update(&update_ctx, id);
+}
+
void id_tag_update_ntree_special(Main *bmain, Depsgraph *graph, ID *id, int flag)
{
bNodeTree *ntree = NULL;
@@ -421,6 +429,9 @@ void deg_graph_id_tag_update(Main *bmain, Depsgraph *graph, ID *id, int flag)
if (flag & DEG_TAG_BASE_FLAGS_UPDATE) {
id_tag_update_base_flags(graph, id_node);
}
+ if (flag & DEG_TAG_EDITORS_UPDATE) {
+ id_tag_update_editors_update(bmain, graph, id);
+ }
id_tag_update_ntree_special(bmain, graph, id, flag);
}
@@ -445,14 +456,6 @@ void deg_graph_on_visible_update(Main *bmain, Depsgraph *graph)
/* Make sure objects are up to date. */
foreach (DEG::IDDepsNode *id_node, graph->id_nodes) {
const ID_Type id_type = GS(id_node->id_orig->name);
- /* TODO(sergey): Special exception for now. */
- if (id_type == ID_MSK) {
- deg_graph_id_tag_update(bmain, graph, id_node->id_orig, 0);
- }
- if (id_type != ID_OB) {
- /* Ignore non-object nodes on visibility changes. */
- continue;
- }
int flag = 0;
/* We only tag components which needs an update. Tagging everything is
* not a good idea because that might reset particles cache (or any
@@ -502,7 +505,7 @@ void DEG_graph_id_tag_update(struct Main *bmain,
DEG::deg_graph_id_tag_update(bmain, graph, id, flag);
}
-/* Tag given ID type for update. */
+/* Mark a particular datablock type as having changing. */
void DEG_id_type_tag(Main *bmain, short id_type)
{
if (id_type == ID_NT) {
@@ -552,7 +555,10 @@ void DEG_on_visible_update(Main *bmain, const bool UNUSED(do_time))
/* Check if something was changed in the database and inform
* editors about this.
*/
-void DEG_ids_check_recalc(Main *bmain, Scene *scene, bool time)
+void DEG_ids_check_recalc(Main *bmain,
+ Scene *scene,
+ ViewLayer *view_layer,
+ bool time)
{
ListBase *lbarray[MAX_LIBARRAY];
int a;
@@ -570,7 +576,11 @@ void DEG_ids_check_recalc(Main *bmain, Scene *scene, bool time)
}
}
- DEG::deg_editors_scene_update(bmain, scene, (updated || time));
+ DEGEditorUpdateContext update_ctx = {NULL};
+ update_ctx.bmain = bmain;
+ update_ctx.scene = scene;
+ update_ctx.view_layer = view_layer;
+ DEG::deg_editors_scene_update(&update_ctx, (updated || time));
}
void DEG_ids_clear_recalc(Main *bmain)
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
index 99efd633524..97e38af4367 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
@@ -653,7 +653,7 @@ ID *deg_expand_copy_on_write_datablock(const Depsgraph *depsgraph,
switch (id_type) {
case ID_SCE:
{
- done = scene_copy_inplace_no_main((Scene *)id_orig, (Scene*)id_cow);
+ done = scene_copy_inplace_no_main((Scene *)id_orig, (Scene *)id_cow);
break;
}
case ID_ME:
@@ -746,9 +746,15 @@ ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph,
* Note that we never free GPU materials from here since that's not
* safe for threading and GPU materials are likely to be re-used.
*/
+ /* TODO(sergey): Either move this to an utility function or redesign
+ * Copy-on-Write components in a way that only needed parts are being
+ * copied over.
+ */
ListBase gpumaterial_backup;
ListBase *gpumaterial_ptr = NULL;
Mesh *mesh_evaluated = NULL;
+ IDProperty *base_collection_properties = NULL;
+ short base_flag = 0;
if (check_datablock_expanded(id_cow)) {
switch (id_type) {
case ID_MA:
@@ -778,6 +784,9 @@ ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph,
object->data = mesh_evaluated->id.newid;
}
}
+ /* Make a backup of base flags. */
+ base_collection_properties = object->base_collection_properties;
+ base_flag = object->base_flag;
break;
}
default:
@@ -795,8 +804,8 @@ ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph,
*gpumaterial_ptr = gpumaterial_backup;
}
if (id_type == ID_OB) {
+ Object *object = (Object *)id_cow;
if (mesh_evaluated != NULL) {
- Object *object = (Object *)id_cow;
object->mesh_evaluated = mesh_evaluated;
/* Do same thing as object update: override actual object data
* pointer with evaluated datablock.
@@ -811,6 +820,10 @@ ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph,
((Mesh *)mesh_evaluated->id.newid)->edit_btmesh;
}
}
+ if (base_collection_properties != NULL) {
+ object->base_collection_properties = base_collection_properties;
+ object->base_flag = base_flag;
+ }
}
return id_cow;
}
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
index 715a95432c0..a30812c692f 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
@@ -56,6 +56,11 @@ extern "C" {
namespace DEG {
enum {
+ ID_STATE_NONE = 0,
+ ID_STATE_MODIFIED = 1,
+};
+
+enum {
COMPONENT_STATE_NONE = 0,
COMPONENT_STATE_SCHEDULED = 1,
COMPONENT_STATE_DONE = 2,
@@ -63,208 +68,201 @@ enum {
typedef std::deque<OperationDepsNode *> FlushQueue;
-static void flush_init_func(void *data_v, int i)
+namespace {
+
+void flush_init_operation_node_func(void *data_v, int i)
{
- /* ID node's done flag is used to avoid multiple editors update
- * for the same ID.
- */
Depsgraph *graph = (Depsgraph *)data_v;
OperationDepsNode *node = graph->operations[i];
- ComponentDepsNode *comp_node = node->owner;
- IDDepsNode *id_node = comp_node->owner;
- id_node->done = 0;
- comp_node->done = COMPONENT_STATE_NONE;
node->scheduled = false;
}
-/* Flush updates from tagged nodes outwards until all affected nodes
- * are tagged.
- */
-void deg_graph_flush_updates(Main *bmain, Depsgraph *graph)
+void flush_init_id_node_func(void *data_v, int i)
{
- const bool use_copy_on_write = DEG_depsgraph_use_copy_on_write();
- /* Sanity check. */
- if (graph == NULL) {
- return;
- }
-
- /* Nothing to update, early out. */
- if (BLI_gset_size(graph->entry_tags) == 0) {
- return;
- }
+ Depsgraph *graph = (Depsgraph *)data_v;
+ IDDepsNode *id_node = graph->id_nodes[i];
+ id_node->done = ID_STATE_NONE;
+ GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp_node, id_node->components)
+ comp_node->done = COMPONENT_STATE_NONE;
+ GHASH_FOREACH_END();
+}
- /* TODO(sergey): With a bit of flag magic we can get rid of this
- * extra loop.
- */
+BLI_INLINE void flush_prepare(Depsgraph *graph)
+{
const int num_operations = graph->operations.size();
- const bool do_threads = num_operations > 256;
- BLI_task_parallel_range(0,
- num_operations,
+ BLI_task_parallel_range(0, num_operations,
+ graph,
+ flush_init_operation_node_func,
+ (num_operations > 256));
+ const int num_id_nodes = graph->id_nodes.size();
+ BLI_task_parallel_range(0, num_id_nodes,
graph,
- flush_init_func,
- do_threads);
+ flush_init_id_node_func,
+ (num_id_nodes > 256));
+}
- FlushQueue queue;
- /* Starting from the tagged "entry" nodes, flush outwards... */
- /* NOTE: Also need to ensure that for each of these, there is a path back to
- * root, or else they won't be done.
- * NOTE: Count how many nodes we need to handle - entry nodes may be
- * component nodes which don't count for this purpose!
- */
+BLI_INLINE void flush_schedule_entrypoints(Depsgraph *graph, FlushQueue *queue)
+{
GSET_FOREACH_BEGIN(OperationDepsNode *, op_node, graph->entry_tags)
{
- queue.push_back(op_node);
+ queue->push_back(op_node);
op_node->scheduled = true;
}
GSET_FOREACH_END();
+}
- int num_flushed_objects = 0;
- while (!queue.empty()) {
- OperationDepsNode *node = queue.front();
- queue.pop_front();
-
- for (;;) {
- node->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
+BLI_INLINE void flush_handle_id_node(IDDepsNode *id_node)
+{
+ id_node->done = ID_STATE_MODIFIED;
+}
- ComponentDepsNode *comp_node = node->owner;
- IDDepsNode *id_node = comp_node->owner;
+/* TODO(sergey): We can reduce number of arguments here. */
+BLI_INLINE void flush_handle_component_node(Depsgraph *graph,
+ IDDepsNode *id_node,
+ ComponentDepsNode *comp_node,
+ bool use_copy_on_write,
+ FlushQueue *queue)
+{
+ /* We only handle component once. */
+ if (comp_node->done == COMPONENT_STATE_DONE) {
+ return;
+ }
+ comp_node->done = COMPONENT_STATE_DONE;
+ /* Currently this is needed to get object->mesh to be replaced with
+ * original mesh (rather than being evaluated_mesh).
+ *
+ * TODO(sergey): This is something we need to avoid.
+ */
+ if (use_copy_on_write && comp_node->depends_on_cow()) {
+ ComponentDepsNode *cow_comp =
+ id_node->find_component(DEG_NODE_TYPE_COPY_ON_WRITE);
+ cow_comp->tag_update(graph);
+ }
+ /* Tag all required operations in component for update. */
+ foreach (OperationDepsNode *op, comp_node->operations) {
+ /* We don't want to flush tags in "upstream" direction for
+ * certain types of operations.
+ *
+ * TODO(sergey): Need a more generic solution for this.
+ */
+ if (op->opcode == DEG_OPCODE_PARTICLE_SETTINGS_EVAL) {
+ continue;
+ }
+ op->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
+ }
+ /* When some target changes bone, we might need to re-run the
+ * whole IK solver, otherwise result might be unpredictable.
+ */
+ if (comp_node->type == DEG_NODE_TYPE_BONE) {
+ ComponentDepsNode *pose_comp =
+ id_node->find_component(DEG_NODE_TYPE_EVAL_POSE);
+ BLI_assert(pose_comp != NULL);
+ if (pose_comp->done == COMPONENT_STATE_NONE) {
+ queue->push_front(pose_comp->get_entry_operation());
+ pose_comp->done = COMPONENT_STATE_SCHEDULED;
+ }
+ }
+}
- /* TODO(sergey): Do we need to pass original or evaluated ID here? */
- ID *id_orig = id_node->id_orig;
- ID *id_cow = id_node->id_cow;
- if (id_node->done == 0) {
- /* Copy tag from original data to CoW storage.
- * This is because DEG_id_tag_update() sets tags on original
- * data.
- */
- id_cow->tag |= (id_orig->tag & LIB_TAG_ID_RECALC_ALL);
- if (deg_copy_on_write_is_expanded(id_cow)) {
- deg_editors_id_update(bmain, id_cow);
- }
- lib_id_recalc_tag(bmain, id_orig);
- /* TODO(sergey): For until we've got proper data nodes in the graph. */
- lib_id_recalc_data_tag(bmain, id_orig);
+/* Schedule children of the given operation node for traversal.
+ *
+ * One of the children will by-pass the queue and will be returned as a function
+ * return value, so it can start being handled right away, without building too
+ * much of a queue.
+ */
+BLI_INLINE OperationDepsNode *flush_schedule_children(
+ OperationDepsNode *op_node,
+ FlushQueue *queue)
+{
+ OperationDepsNode *result = NULL;
+ foreach (DepsRelation *rel, op_node->outlinks) {
+ OperationDepsNode *to_node = (OperationDepsNode *)rel->to;
+ if (to_node->scheduled == false) {
+ if (result != NULL) {
+ queue->push_front(to_node);
}
-
- if (comp_node->done != COMPONENT_STATE_DONE) {
- /* Currently this is needed to get object->mesh to be replaced with
- * original mesh (rather than being evaluated_mesh).
- *
- * TODO(sergey): This is something we need to avoid.
- */
- if (use_copy_on_write && comp_node->depends_on_cow()) {
- ComponentDepsNode *cow_comp =
- id_node->find_component(DEG_NODE_TYPE_COPY_ON_WRITE);
- cow_comp->tag_update(graph);
- }
-
- Object *object = NULL;
- if (GS(id_orig->name) == ID_OB) {
- object = (Object *)id_orig;
- if (id_node->done == 0) {
- ++num_flushed_objects;
- }
- }
- foreach (OperationDepsNode *op, comp_node->operations) {
- /* We don't want to flush tags in "upstream" direction for
- * certain types of operations.
- *
- * TODO(sergey): Need a more generic solution for this.
- */
- if (op->opcode == DEG_OPCODE_PARTICLE_SETTINGS_EVAL) {
- continue;
- }
- op->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
- }
- if (object != NULL) {
- /* This code is used to preserve those areas which does
- * direct object update,
- *
- * Plus it ensures visibility changes and relations and
- * layers visibility update has proper flags to work with.
- */
- switch (comp_node->type) {
- case DEG_NODE_TYPE_UNDEFINED:
- case DEG_NODE_TYPE_OPERATION:
- case DEG_NODE_TYPE_TIMESOURCE:
- case DEG_NODE_TYPE_ID_REF:
- case DEG_NODE_TYPE_PARAMETERS:
- case DEG_NODE_TYPE_SEQUENCER:
- /* Ignore, does not translate to object component. */
- BLI_assert(!"This should never happen!");
- break;
- case DEG_NODE_TYPE_ANIMATION:
- object->recalc |= OB_RECALC_TIME;
- break;
- case DEG_NODE_TYPE_TRANSFORM:
- object->recalc |= OB_RECALC_OB;
- break;
- case DEG_NODE_TYPE_GEOMETRY:
- case DEG_NODE_TYPE_EVAL_POSE:
- case DEG_NODE_TYPE_BONE:
- case DEG_NODE_TYPE_EVAL_PARTICLES:
- case DEG_NODE_TYPE_SHADING:
- case DEG_NODE_TYPE_CACHE:
- case DEG_NODE_TYPE_PROXY:
- object->recalc |= OB_RECALC_DATA;
- break;
- case DEG_NODE_TYPE_BATCH_CACHE:
- case DEG_NODE_TYPE_SHADING_PARAMETERS:
- case DEG_NODE_TYPE_LAYER_COLLECTIONS:
- case DEG_NODE_TYPE_COPY_ON_WRITE:
- /* Ignore, does not translate to recalc flags. */
- break;
- }
-
- /* TODO : replace with more granular flags */
- object->deg_update_flag |= DEG_RUNTIME_DATA_UPDATE;
- }
- /* When some target changes bone, we might need to re-run the
- * whole IK solver, otherwise result might be unpredictable.
- */
- if (comp_node->type == DEG_NODE_TYPE_BONE) {
- ComponentDepsNode *pose_comp =
- id_node->find_component(DEG_NODE_TYPE_EVAL_POSE);
- BLI_assert(pose_comp != NULL);
- if (pose_comp->done == COMPONENT_STATE_NONE) {
- queue.push_front(pose_comp->get_entry_operation());
- pose_comp->done = COMPONENT_STATE_SCHEDULED;
- }
- }
+ else {
+ result = to_node;
}
+ to_node->scheduled = true;
+ }
+ }
+ return result;
+}
- id_node->done = 1;
- comp_node->done = COMPONENT_STATE_DONE;
+BLI_INLINE void flush_editors_id_update(Main *bmain,
+ Depsgraph *graph,
+ const DEGEditorUpdateContext *update_ctx)
+{
+ foreach (IDDepsNode *id_node, graph->id_nodes) {
+ if (id_node->done != ID_STATE_MODIFIED) {
+ continue;
+ }
+ /* TODO(sergey): Do we need to pass original or evaluated ID here? */
+ ID *id_orig = id_node->id_orig;
+ ID *id_cow = id_node->id_cow;
+ /* Copy tag from original data to CoW storage.
+ * This is because DEG_id_tag_update() sets tags on original
+ * data.
+ */
+ id_cow->tag |= (id_orig->tag & LIB_TAG_ID_RECALC_ALL);
+ if (deg_copy_on_write_is_expanded(id_cow)) {
+ deg_editors_id_update(update_ctx, id_cow);
+ }
+ lib_id_recalc_tag(bmain, id_orig);
+ /* TODO(sergey): For until we've got proper data nodes in the graph. */
+ lib_id_recalc_data_tag(bmain, id_orig);
+ }
+}
- /* Flush to nodes along links... */
- /* TODO(sergey): This is mainly giving speedup due ot less queue pushes, which
- * reduces number of memory allocations.
- *
- * We should try solve the allocation issue instead of doing crazy things here.
- */
- if (node->outlinks.size() == 1) {
- OperationDepsNode *to_node = (OperationDepsNode *)node->outlinks[0]->to;
- if (to_node->scheduled == false) {
- to_node->scheduled = true;
- node = to_node;
- }
- else {
- break;
- }
- }
- else {
- foreach (DepsRelation *rel, node->outlinks) {
- OperationDepsNode *to_node = (OperationDepsNode *)rel->to;
- if (to_node->scheduled == false) {
- queue.push_front(to_node);
- to_node->scheduled = true;
- }
- }
- break;
- }
+} // namespace
+
+/* Flush updates from tagged nodes outwards until all affected nodes
+ * are tagged.
+ */
+void deg_graph_flush_updates(Main *bmain, Depsgraph *graph)
+{
+ const bool use_copy_on_write = DEG_depsgraph_use_copy_on_write();
+ /* Sanity checks. */
+ BLI_assert(bmain != NULL);
+ BLI_assert(graph != NULL);
+ /* Nothing to update, early out. */
+ if (BLI_gset_size(graph->entry_tags) == 0) {
+ return;
+ }
+ /* Reset all flags, get ready for the flush. */
+ flush_prepare(graph);
+ /* Starting from the tagged "entry" nodes, flush outwards. */
+ FlushQueue queue;
+ flush_schedule_entrypoints(graph, &queue);
+ /* Prepare update context for editors. */
+ DEGEditorUpdateContext update_ctx = {
+ bmain,
+ graph->scene,
+ graph->view_layer,
+ };
+ /* Do actual flush. */
+ while (!queue.empty()) {
+ OperationDepsNode *op_node = queue.front();
+ queue.pop_front();
+ while (op_node != NULL) {
+ /* Tag operation as required for update. */
+ op_node->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
+ /* Inform corresponding ID and component nodes about the change. */
+ ComponentDepsNode *comp_node = op_node->owner;
+ IDDepsNode *id_node = comp_node->owner;
+ flush_handle_id_node(id_node);
+ flush_handle_component_node(graph,
+ id_node,
+ comp_node,
+ use_copy_on_write,
+ &queue);
+ /* Flush to nodes along links. */
+ op_node = flush_schedule_children(op_node, &queue);
}
}
- DEG_DEBUG_PRINTF("Update flushed to %d objects\n", num_flushed_objects);
+ /* Inform editors about all changes. */
+ flush_editors_id_update(bmain, graph, &update_ctx);
}
static void graph_clear_func(void *data_v, int i)
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 9c806f26fda..8339b6b8720 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -137,6 +137,7 @@ data_to_c_simple(engines/eevee/shaders/lamps_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lightprobe_lib.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl SRC)
+data_to_c_simple(engines/eevee/shaders/lightprobe_filter_visibility_frag.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lightprobe_geom.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lightprobe_vert.glsl SRC)
data_to_c_simple(engines/eevee/shaders/lightprobe_cube_display_frag.glsl SRC)
diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h
index da7524754de..ba0f8681f10 100644
--- a/source/blender/draw/DRW_engine.h
+++ b/source/blender/draw/DRW_engine.h
@@ -30,9 +30,11 @@ struct ARegion;
struct CollectionEngineSettings;
struct Depsgraph;
struct DRWPass;
+struct Main;
struct Material;
struct Scene;
struct DrawEngineType;
+struct ID;
struct IDProperty;
struct bContext;
struct Object;
@@ -68,13 +70,22 @@ void DRW_engine_viewport_data_size_get(
const void *engine_type,
int *r_fbl_len, int *r_txl_len, int *r_psl_len, int *r_stl_len);
-void DRW_notify_view_update(const struct bContext *C);
+typedef struct DRWUpdateContext {
+ struct Main *bmain;
+ struct Scene *scene;
+ struct ViewLayer *view_layer;
+ struct ARegion *ar;
+ struct View3D *v3d;
+ struct RenderEngineType *engine_type;
+} DRWUpdateContext;
+void DRW_notify_view_update(const DRWUpdateContext *update_ctx);
+void DRW_notify_id_update(const DRWUpdateContext *update_ctx, struct ID *id);
void DRW_draw_view(const struct bContext *C);
void DRW_draw_render_loop_ex(
struct Depsgraph *graph,
- struct RenderEngineType *engine,
+ struct RenderEngineType *engine_type,
struct ARegion *ar, struct View3D *v3d,
const struct bContext *evil_C);
void DRW_draw_render_loop(
@@ -82,7 +93,7 @@ void DRW_draw_render_loop(
struct ARegion *ar, struct View3D *v3d);
void DRW_draw_render_loop_offscreen(
struct Depsgraph *graph,
- struct RenderEngineType *engine,
+ struct RenderEngineType *engine_type,
struct ARegion *ar, struct View3D *v3d,
struct GPUOffScreen *ofs);
void DRW_draw_select_loop(
diff --git a/source/blender/draw/engines/basic/basic_engine.c b/source/blender/draw/engines/basic/basic_engine.c
index 92ffa8a1794..10dfe7b5996 100644
--- a/source/blender/draw/engines/basic/basic_engine.c
+++ b/source/blender/draw/engines/basic/basic_engine.c
@@ -111,7 +111,7 @@ typedef struct BASIC_PrivateData {
/* Functions */
-static void BASIC_engine_init(void *vedata)
+static void basic_engine_init(void *vedata)
{
BASIC_StorageList *stl = ((BASIC_Data *)vedata)->stl;
BASIC_TextureList *txl = ((BASIC_Data *)vedata)->txl;
@@ -144,7 +144,7 @@ static void BASIC_engine_init(void *vedata)
#endif
}
-static void BASIC_cache_init(void *vedata)
+static void basic_cache_init(void *vedata)
{
BASIC_PassList *psl = ((BASIC_Data *)vedata)->psl;
BASIC_StorageList *stl = ((BASIC_Data *)vedata)->stl;
@@ -174,7 +174,7 @@ static void BASIC_cache_init(void *vedata)
}
}
-static void BASIC_cache_populate(void *vedata, Object *ob)
+static void basic_cache_populate(void *vedata, Object *ob)
{
BASIC_StorageList *stl = ((BASIC_Data *)vedata)->stl;
@@ -193,14 +193,14 @@ static void BASIC_cache_populate(void *vedata, Object *ob)
}
}
-static void BASIC_cache_finish(void *vedata)
+static void basic_cache_finish(void *vedata)
{
BASIC_StorageList *stl = ((BASIC_Data *)vedata)->stl;
UNUSED_VARS(stl);
}
-static void BASIC_draw_scene(void *vedata)
+static void basic_draw_scene(void *vedata)
{
BASIC_PassList *psl = ((BASIC_Data *)vedata)->psl;
@@ -244,24 +244,25 @@ static void BASIC_draw_scene(void *vedata)
}
}
-static void BASIC_engine_free(void)
+static void basic_engine_free(void)
{
/* all shaders are builtin */
}
-static const DrawEngineDataSize BASIC_data_size = DRW_VIEWPORT_DATA_SIZE(BASIC_Data);
+static const DrawEngineDataSize basic_data_size = DRW_VIEWPORT_DATA_SIZE(BASIC_Data);
DrawEngineType draw_engine_basic_type = {
NULL, NULL,
N_("Basic"),
- &BASIC_data_size,
- &BASIC_engine_init,
- &BASIC_engine_free,
- &BASIC_cache_init,
- &BASIC_cache_populate,
- &BASIC_cache_finish,
+ &basic_data_size,
+ &basic_engine_init,
+ &basic_engine_free,
+ &basic_cache_init,
+ &basic_cache_populate,
+ &basic_cache_finish,
+ NULL,
+ &basic_draw_scene,
NULL,
- &BASIC_draw_scene,
NULL,
};
diff --git a/source/blender/draw/engines/clay/clay_engine.c b/source/blender/draw/engines/clay/clay_engine.c
index fe81e1e484c..01f89ae6b1c 100644
--- a/source/blender/draw/engines/clay/clay_engine.c
+++ b/source/blender/draw/engines/clay/clay_engine.c
@@ -197,7 +197,7 @@ static void clay_view_layer_data_free(void *storage)
static CLAY_ViewLayerData *CLAY_view_layer_data_get(void)
{
- CLAY_ViewLayerData **sldata = (CLAY_ViewLayerData **)DRW_view_layer_engine_data_get(&draw_engine_clay_type, &clay_view_layer_data_free);
+ CLAY_ViewLayerData **sldata = (CLAY_ViewLayerData **)DRW_view_layer_engine_data_ensure(&draw_engine_clay_type, &clay_view_layer_data_free);
if (*sldata == NULL) {
*sldata = MEM_callocN(sizeof(**sldata), "CLAY_ViewLayerData");
@@ -322,7 +322,7 @@ static struct GPUTexture *create_jitter_texture(int num_samples)
return DRW_texture_create_2D(64, 64, DRW_TEX_RGB_16, DRW_TEX_FILTER | DRW_TEX_WRAP, &jitter[0][0]);
}
-static void CLAY_engine_init(void *vedata)
+static void clay_engine_init(void *vedata)
{
CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl;
CLAY_FramebufferList *fbl = ((CLAY_Data *)vedata)->fbl;
@@ -702,7 +702,7 @@ static DRWShadingGroup *CLAY_object_shgrp_default_mode_get(
return CLAY_object_shgrp_get(vedata, ob, stl, psl, use_flat);
}
-static void CLAY_cache_init(void *vedata)
+static void clay_cache_init(void *vedata)
{
CLAY_PassList *psl = ((CLAY_Data *)vedata)->psl;
CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl;
@@ -746,7 +746,7 @@ static void CLAY_cache_init(void *vedata)
}
}
-static void CLAY_cache_populate(void *vedata, Object *ob)
+static void clay_cache_populate(void *vedata, Object *ob)
{
CLAY_PassList *psl = ((CLAY_Data *)vedata)->psl;
CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl;
@@ -826,7 +826,7 @@ static void CLAY_cache_populate(void *vedata, Object *ob)
}
}
-static void CLAY_cache_finish(void *vedata)
+static void clay_cache_finish(void *vedata)
{
CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl;
@@ -834,7 +834,7 @@ static void CLAY_cache_finish(void *vedata)
DRW_uniformbuffer_update(stl->hair_mat_ubo, &stl->storage->hair_mat_storage);
}
-static void CLAY_draw_scene(void *vedata)
+static void clay_draw_scene(void *vedata)
{
CLAY_PassList *psl = ((CLAY_Data *)vedata)->psl;
@@ -866,7 +866,7 @@ static void CLAY_draw_scene(void *vedata)
DRW_draw_pass(psl->hair_pass);
}
-static void CLAY_layer_collection_settings_create(RenderEngine *UNUSED(engine), IDProperty *props)
+static void clay_layer_collection_settings_create(RenderEngine *UNUSED(engine), IDProperty *props)
{
BLI_assert(props &&
props->type == IDP_GROUP &&
@@ -885,7 +885,7 @@ static void CLAY_layer_collection_settings_create(RenderEngine *UNUSED(engine),
BKE_collection_engine_property_add_float(props, "hair_brightness_randomness", 0.0f);
}
-static void CLAY_view_layer_settings_create(RenderEngine *UNUSED(engine), IDProperty *props)
+static void clay_view_layer_settings_create(RenderEngine *UNUSED(engine), IDProperty *props)
{
BLI_assert(props &&
props->type == IDP_GROUP &&
@@ -894,7 +894,7 @@ static void CLAY_view_layer_settings_create(RenderEngine *UNUSED(engine), IDProp
BKE_collection_engine_property_add_int(props, "ssao_samples", 16);
}
-static void CLAY_engine_free(void)
+static void clay_engine_free(void)
{
DRW_SHADER_FREE_SAFE(e_data.clay_sh);
DRW_SHADER_FREE_SAFE(e_data.clay_flat_sh);
@@ -902,19 +902,20 @@ static void CLAY_engine_free(void)
DRW_TEXTURE_FREE_SAFE(e_data.matcap_array);
}
-static const DrawEngineDataSize CLAY_data_size = DRW_VIEWPORT_DATA_SIZE(CLAY_Data);
+static const DrawEngineDataSize clay_data_size = DRW_VIEWPORT_DATA_SIZE(CLAY_Data);
DrawEngineType draw_engine_clay_type = {
NULL, NULL,
N_("Clay"),
- &CLAY_data_size,
- &CLAY_engine_init,
- &CLAY_engine_free,
- &CLAY_cache_init,
- &CLAY_cache_populate,
- &CLAY_cache_finish,
+ &clay_data_size,
+ &clay_engine_init,
+ &clay_engine_free,
+ &clay_cache_init,
+ &clay_cache_populate,
+ &clay_cache_finish,
+ NULL,
+ &clay_draw_scene,
NULL,
- &CLAY_draw_scene,
NULL,
};
@@ -922,8 +923,8 @@ RenderEngineType DRW_engine_viewport_clay_type = {
NULL, NULL,
CLAY_ENGINE, N_("Clay"), RE_INTERNAL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- &CLAY_layer_collection_settings_create,
- &CLAY_view_layer_settings_create,
+ &clay_layer_collection_settings_create,
+ &clay_view_layer_settings_create,
&draw_engine_clay_type,
{NULL, NULL, NULL}
};
@@ -931,4 +932,4 @@ RenderEngineType DRW_engine_viewport_clay_type = {
#undef CLAY_ENGINE
-#endif
+#endif /* WITH_CLAY_ENGINE */
diff --git a/source/blender/draw/engines/eevee/eevee_data.c b/source/blender/draw/engines/eevee/eevee_data.c
index 6b95844591d..d5582a498a4 100644
--- a/source/blender/draw/engines/eevee/eevee_data.c
+++ b/source/blender/draw/engines/eevee/eevee_data.c
@@ -55,6 +55,7 @@ static void eevee_view_layer_data_free(void *storage)
DRW_FRAMEBUFFER_FREE_SAFE(sldata->probe_fb);
DRW_FRAMEBUFFER_FREE_SAFE(sldata->probe_filter_fb);
DRW_TEXTURE_FREE_SAFE(sldata->probe_rt);
+ DRW_TEXTURE_FREE_SAFE(sldata->probe_depth_rt);
DRW_TEXTURE_FREE_SAFE(sldata->probe_pool);
DRW_TEXTURE_FREE_SAFE(sldata->irradiance_pool);
DRW_TEXTURE_FREE_SAFE(sldata->irradiance_rt);
@@ -80,7 +81,13 @@ static void eevee_lightprobe_data_free(void *storage)
EEVEE_ViewLayerData *EEVEE_view_layer_data_get(void)
{
- EEVEE_ViewLayerData **sldata = (EEVEE_ViewLayerData **)DRW_view_layer_engine_data_get(
+ return (EEVEE_ViewLayerData *)DRW_view_layer_engine_data_get(
+ &draw_engine_eevee_type);
+}
+
+EEVEE_ViewLayerData *EEVEE_view_layer_data_ensure(void)
+{
+ EEVEE_ViewLayerData **sldata = (EEVEE_ViewLayerData **)DRW_view_layer_engine_data_ensure(
&draw_engine_eevee_type, &eevee_view_layer_data_free);
if (*sldata == NULL) {
@@ -92,7 +99,13 @@ EEVEE_ViewLayerData *EEVEE_view_layer_data_get(void)
EEVEE_ObjectEngineData *EEVEE_object_data_get(Object *ob)
{
- EEVEE_ObjectEngineData **oedata = (EEVEE_ObjectEngineData **)DRW_object_engine_data_get(
+ return (EEVEE_ObjectEngineData *)DRW_object_engine_data_get(
+ ob, &draw_engine_eevee_type);
+}
+
+EEVEE_ObjectEngineData *EEVEE_object_data_ensure(Object *ob)
+{
+ EEVEE_ObjectEngineData **oedata = (EEVEE_ObjectEngineData **)DRW_object_engine_data_ensure(
ob, &draw_engine_eevee_type, NULL);
if (*oedata == NULL) {
@@ -104,11 +117,18 @@ EEVEE_ObjectEngineData *EEVEE_object_data_get(Object *ob)
EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_get(Object *ob)
{
- EEVEE_LightProbeEngineData **pedata = (EEVEE_LightProbeEngineData **)DRW_object_engine_data_get(
+ return (EEVEE_LightProbeEngineData *)DRW_object_engine_data_get(
+ ob, &draw_engine_eevee_type);
+}
+
+EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_ensure(Object *ob)
+{
+ EEVEE_LightProbeEngineData **pedata = (EEVEE_LightProbeEngineData **)DRW_object_engine_data_ensure(
ob, &draw_engine_eevee_type, &eevee_lightprobe_data_free);
if (*pedata == NULL) {
*pedata = MEM_callocN(sizeof(**pedata), "EEVEE_LightProbeEngineData");
+ (*pedata)->need_full_update = true;
(*pedata)->need_update = true;
}
@@ -117,7 +137,13 @@ EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_get(Object *ob)
EEVEE_LampEngineData *EEVEE_lamp_data_get(Object *ob)
{
- EEVEE_LampEngineData **ledata = (EEVEE_LampEngineData **)DRW_object_engine_data_get(
+ return (EEVEE_LampEngineData *)DRW_object_engine_data_get(
+ ob, &draw_engine_eevee_type);
+}
+
+EEVEE_LampEngineData *EEVEE_lamp_data_ensure(Object *ob)
+{
+ EEVEE_LampEngineData **ledata = (EEVEE_LampEngineData **)DRW_object_engine_data_ensure(
ob, &draw_engine_eevee_type, &eevee_lamp_data_free);
if (*ledata == NULL) {
diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c
index f059fbe2268..a20b1afe3d4 100644
--- a/source/blender/draw/engines/eevee/eevee_engine.c
+++ b/source/blender/draw/engines/eevee/eevee_engine.c
@@ -44,13 +44,13 @@ extern GlobalsUboStorage ts;
/* *********** FUNCTIONS *********** */
-static void EEVEE_engine_init(void *ved)
+static void eevee_engine_init(void *ved)
{
EEVEE_Data *vedata = (EEVEE_Data *)ved;
EEVEE_TextureList *txl = vedata->txl;
EEVEE_FramebufferList *fbl = vedata->fbl;
EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
- EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_get();
+ EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
if (!stl->g_data) {
/* Alloc transient pointers */
@@ -82,10 +82,10 @@ static void EEVEE_engine_init(void *ved)
}
}
-static void EEVEE_cache_init(void *vedata)
+static void eevee_cache_init(void *vedata)
{
EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
- EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_get();
+ EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
EEVEE_bloom_cache_init(sldata, vedata);
EEVEE_depth_of_field_cache_init(sldata, vedata);
@@ -101,9 +101,9 @@ static void EEVEE_cache_init(void *vedata)
EEVEE_volumes_cache_init(sldata, vedata);
}
-static void EEVEE_cache_populate(void *vedata, Object *ob)
+static void eevee_cache_populate(void *vedata, Object *ob)
{
- EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_get();
+ EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
const DRWContextState *draw_ctx = DRW_context_state_get();
const bool is_active = (ob == draw_ctx->obact);
@@ -128,8 +128,6 @@ static void EEVEE_cache_populate(void *vedata, Object *ob)
}
else {
BLI_addtail(&sldata->shadow_casters, BLI_genericNodeN(ob));
- EEVEE_ObjectEngineData *oedata = EEVEE_object_data_get(ob);
- oedata->need_update = ((ob->deg_update_flag & DEG_RUNTIME_DATA_UPDATE) != 0);
}
}
}
@@ -151,21 +149,21 @@ static void EEVEE_cache_populate(void *vedata, Object *ob)
}
}
-static void EEVEE_cache_finish(void *vedata)
+static void eevee_cache_finish(void *vedata)
{
- EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_get();
+ EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
EEVEE_materials_cache_finish(vedata);
EEVEE_lights_cache_finish(sldata);
EEVEE_lightprobes_cache_finish(sldata, vedata);
}
-static void EEVEE_draw_scene(void *vedata)
+static void eevee_draw_scene(void *vedata)
{
EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl;
EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
EEVEE_FramebufferList *fbl = ((EEVEE_Data *)vedata)->fbl;
- EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_get();
+ EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure();
/* Default framebuffer and texture */
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
@@ -279,7 +277,7 @@ static void EEVEE_draw_scene(void *vedata)
stl->g_data->view_updated = false;
}
-static void EEVEE_view_update(void *vedata)
+static void eevee_view_update(void *vedata)
{
EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl;
if (stl->g_data) {
@@ -287,7 +285,27 @@ static void EEVEE_view_update(void *vedata)
}
}
-static void EEVEE_engine_free(void)
+static void eevee_id_update(void *UNUSED(vedata), ID *id)
+{
+ const ID_Type id_type = GS(id->name);
+ if (id_type == ID_OB) {
+ Object *object = (Object *)id;
+ EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(object);
+ if (ped != NULL) {
+ ped->need_full_update = true;
+ }
+ EEVEE_LampEngineData *led = EEVEE_lamp_data_get(object);
+ if (led != NULL) {
+ led->need_update = true;
+ }
+ EEVEE_ObjectEngineData *oedata = EEVEE_object_data_get(object);
+ if (oedata != NULL) {
+ oedata->need_update = true;
+ }
+ }
+}
+
+static void eevee_engine_free(void)
{
EEVEE_bloom_free();
EEVEE_depth_of_field_free();
@@ -303,7 +321,7 @@ static void EEVEE_engine_free(void)
EEVEE_volumes_free();
}
-static void EEVEE_layer_collection_settings_create(RenderEngine *UNUSED(engine), IDProperty *props)
+static void eevee_layer_collection_settings_create(RenderEngine *UNUSED(engine), IDProperty *props)
{
BLI_assert(props &&
props->type == IDP_GROUP &&
@@ -312,7 +330,7 @@ static void EEVEE_layer_collection_settings_create(RenderEngine *UNUSED(engine),
UNUSED_VARS_NDEBUG(props);
}
-static void EEVEE_view_layer_settings_create(RenderEngine *UNUSED(engine), IDProperty *props)
+static void eevee_view_layer_settings_create(RenderEngine *UNUSED(engine), IDProperty *props)
{
BLI_assert(props &&
props->type == IDP_GROUP &&
@@ -320,6 +338,7 @@ static void EEVEE_view_layer_settings_create(RenderEngine *UNUSED(engine), IDPro
BKE_collection_engine_property_add_int(props, "gi_diffuse_bounces", 3);
BKE_collection_engine_property_add_int(props, "gi_cubemap_resolution", 512);
+ BKE_collection_engine_property_add_int(props, "gi_visibility_resolution", 32);
BKE_collection_engine_property_add_int(props, "taa_samples", 8);
@@ -381,27 +400,29 @@ static void EEVEE_view_layer_settings_create(RenderEngine *UNUSED(engine), IDPro
BKE_collection_engine_property_add_bool(props, "shadow_high_bitdepth", false);
}
-static const DrawEngineDataSize EEVEE_data_size = DRW_VIEWPORT_DATA_SIZE(EEVEE_Data);
+static const DrawEngineDataSize eevee_data_size = DRW_VIEWPORT_DATA_SIZE(EEVEE_Data);
DrawEngineType draw_engine_eevee_type = {
NULL, NULL,
N_("Eevee"),
- &EEVEE_data_size,
- &EEVEE_engine_init,
- &EEVEE_engine_free,
- &EEVEE_cache_init,
- &EEVEE_cache_populate,
- &EEVEE_cache_finish,
- &EEVEE_draw_scene,
+ &eevee_data_size,
+ &eevee_engine_init,
+ &eevee_engine_free,
+ &eevee_cache_init,
+ &eevee_cache_populate,
+ &eevee_cache_finish,
+ &eevee_draw_scene,
NULL, //&EEVEE_draw_scene
- &EEVEE_view_update,
+ &eevee_view_update,
+ &eevee_id_update,
};
RenderEngineType DRW_engine_viewport_eevee_type = {
NULL, NULL,
EEVEE_ENGINE, N_("Eevee"), RE_INTERNAL | RE_USE_SHADING_NODES,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- &EEVEE_layer_collection_settings_create, &EEVEE_view_layer_settings_create,
+ &eevee_layer_collection_settings_create,
+ &eevee_view_layer_settings_create,
&draw_engine_eevee_type,
{NULL, NULL, NULL}
};
diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c
index a58e6e20c58..d7ccc1a5336 100644
--- a/source/blender/draw/engines/eevee/eevee_lightprobes.c
+++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c
@@ -46,12 +46,30 @@
#include "ED_screen.h"
-#define IRRADIANCE_POOL_SIZE 1024
+/* Rounded to nearest PowerOfTwo */
+#if defined(IRRADIANCE_SH_L2)
+#define IRRADIANCE_SAMPLE_SIZE_X 4 /* 3 in reality */
+#define IRRADIANCE_SAMPLE_SIZE_Y 4 /* 3 in reality */
+#elif defined(IRRADIANCE_CUBEMAP)
+#define IRRADIANCE_SAMPLE_SIZE_X 8
+#define IRRADIANCE_SAMPLE_SIZE_Y 8
+#elif defined(IRRADIANCE_HL2)
+#define IRRADIANCE_SAMPLE_SIZE_X 4 /* 3 in reality */
+#define IRRADIANCE_SAMPLE_SIZE_Y 2
+#endif
+
+#define IRRADIANCE_MAX_POOL_LAYER 256 /* OpenGL 3.3 core requirement, can be extended but it's already very big */
+#define IRRADIANCE_MAX_POOL_SIZE 1024
+#define MAX_IRRADIANCE_SAMPLES \
+ (IRRADIANCE_MAX_POOL_SIZE / IRRADIANCE_SAMPLE_SIZE_X) * \
+ (IRRADIANCE_MAX_POOL_SIZE / IRRADIANCE_SAMPLE_SIZE_Y)
+#define HAMMERSLEY_SIZE 1024
static struct {
struct GPUShader *probe_default_sh;
struct GPUShader *probe_filter_glossy_sh;
struct GPUShader *probe_filter_diffuse_sh;
+ struct GPUShader *probe_filter_visibility_sh;
struct GPUShader *probe_grid_fill_sh;
struct GPUShader *probe_grid_display_sh;
struct GPUShader *probe_planar_display_sh;
@@ -62,7 +80,6 @@ static struct {
struct GPUTexture *planar_pool_placeholder;
struct GPUTexture *depth_placeholder;
struct GPUTexture *depth_array_placeholder;
- struct GPUTexture *cube_face_depth;
struct GPUTexture *cube_face_minmaxz;
int update_world;
@@ -73,6 +90,7 @@ extern char datatoc_background_vert_glsl[];
extern char datatoc_default_world_frag_glsl[];
extern char datatoc_lightprobe_filter_glossy_frag_glsl[];
extern char datatoc_lightprobe_filter_diffuse_frag_glsl[];
+extern char datatoc_lightprobe_filter_visibility_frag_glsl[];
extern char datatoc_lightprobe_geom_glsl[];
extern char datatoc_lightprobe_vert_glsl[];
extern char datatoc_lightprobe_planar_display_frag_glsl[];
@@ -95,6 +113,21 @@ extern GlobalsUboStorage ts;
/* *********** FUNCTIONS *********** */
+static void irradiance_pool_size_get(int visibility_size, int total_samples, int r_size[3])
+{
+ /* Compute how many irradiance samples we can store per visibility sample. */
+ int irr_per_vis = (visibility_size / IRRADIANCE_SAMPLE_SIZE_X) *
+ (visibility_size / IRRADIANCE_SAMPLE_SIZE_Y);
+
+ /* The irradiance itself take one layer, hence the +1 */
+ int layer_ct = MIN2(irr_per_vis + 1, IRRADIANCE_MAX_POOL_LAYER);
+
+ int texel_ct = (int)ceilf((float)total_samples / (float)(layer_ct - 1));
+ r_size[0] = visibility_size * max_ii(1, min_ii(texel_ct, (IRRADIANCE_MAX_POOL_SIZE / visibility_size)));
+ r_size[1] = visibility_size * max_ii(1, (texel_ct / (IRRADIANCE_MAX_POOL_SIZE / visibility_size)));
+ r_size[2] = layer_ct;
+}
+
static struct GPUTexture *create_hammersley_sample_texture(int samples)
{
struct GPUTexture *tex;
@@ -157,110 +190,110 @@ static void planar_pool_ensure_alloc(EEVEE_Data *vedata, int num_planar_ref)
}
}
-void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(vedata))
+static void lightprobe_shaders_init(void)
{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- ViewLayer *view_layer = draw_ctx->view_layer;
- IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE);
-
- /* Shaders */
- if (!e_data.probe_filter_glossy_sh) {
- char *shader_str = NULL;
-
- DynStr *ds_frag = BLI_dynstr_new();
- BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_lightprobe_filter_glossy_frag_glsl);
- shader_str = BLI_dynstr_get_cstring(ds_frag);
- BLI_dynstr_free(ds_frag);
-
- e_data.probe_filter_glossy_sh = DRW_shader_create(
- datatoc_lightprobe_vert_glsl, datatoc_lightprobe_geom_glsl, shader_str,
- "#define HAMMERSLEY_SIZE 1024\n"
- "#define NOISE_SIZE 64\n");
-
- e_data.probe_default_sh = DRW_shader_create(
- datatoc_background_vert_glsl, NULL, datatoc_default_world_frag_glsl, NULL);
-
- MEM_freeN(shader_str);
-
- ds_frag = BLI_dynstr_new();
- BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_lightprobe_filter_diffuse_frag_glsl);
- shader_str = BLI_dynstr_get_cstring(ds_frag);
- BLI_dynstr_free(ds_frag);
-
- e_data.probe_filter_diffuse_sh = DRW_shader_create_fullscreen(
- shader_str,
+ const char *filter_defines = "#define HAMMERSLEY_SIZE " STRINGIFY(HAMMERSLEY_SIZE) "\n"
#if defined(IRRADIANCE_SH_L2)
- "#define IRRADIANCE_SH_L2\n"
+ "#define IRRADIANCE_SH_L2\n"
#elif defined(IRRADIANCE_CUBEMAP)
- "#define IRRADIANCE_CUBEMAP\n"
+ "#define IRRADIANCE_CUBEMAP\n"
#elif defined(IRRADIANCE_HL2)
- "#define IRRADIANCE_HL2\n"
+ "#define IRRADIANCE_HL2\n"
#endif
- "#define HAMMERSLEY_SIZE 1024\n"
- "#define NOISE_SIZE 64\n");
-
- MEM_freeN(shader_str);
-
- ds_frag = BLI_dynstr_new();
- BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_irradiance_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_lightprobe_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_lightprobe_grid_display_frag_glsl);
- shader_str = BLI_dynstr_get_cstring(ds_frag);
- BLI_dynstr_free(ds_frag);
-
- e_data.probe_grid_display_sh = DRW_shader_create(
- datatoc_lightprobe_grid_display_vert_glsl, NULL, shader_str,
-#if defined(IRRADIANCE_SH_L2)
- "#define IRRADIANCE_SH_L2\n"
-#elif defined(IRRADIANCE_CUBEMAP)
- "#define IRRADIANCE_CUBEMAP\n"
-#elif defined(IRRADIANCE_HL2)
- "#define IRRADIANCE_HL2\n"
-#endif
- );
+ "#define NOISE_SIZE 64\n";
- MEM_freeN(shader_str);
+ char *shader_str = NULL;
- e_data.probe_grid_fill_sh = DRW_shader_create_fullscreen(datatoc_lightprobe_grid_fill_frag_glsl,
-#if defined(IRRADIANCE_SH_L2)
- "#define IRRADIANCE_SH_L2\n"
-#elif defined(IRRADIANCE_CUBEMAP)
- "#define IRRADIANCE_CUBEMAP\n"
-#elif defined(IRRADIANCE_HL2)
- "#define IRRADIANCE_HL2\n"
-#endif
- );
+ DynStr *ds_frag = BLI_dynstr_new();
+ BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_lightprobe_filter_glossy_frag_glsl);
+ shader_str = BLI_dynstr_get_cstring(ds_frag);
+ BLI_dynstr_free(ds_frag);
+
+ e_data.probe_filter_glossy_sh = DRW_shader_create(
+ datatoc_lightprobe_vert_glsl, datatoc_lightprobe_geom_glsl, shader_str, filter_defines);
+
+ e_data.probe_default_sh = DRW_shader_create(
+ datatoc_background_vert_glsl, NULL, datatoc_default_world_frag_glsl, NULL);
+
+ MEM_freeN(shader_str);
+
+ ds_frag = BLI_dynstr_new();
+ BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_lightprobe_filter_diffuse_frag_glsl);
+ shader_str = BLI_dynstr_get_cstring(ds_frag);
+ BLI_dynstr_free(ds_frag);
+
+ e_data.probe_filter_diffuse_sh = DRW_shader_create_fullscreen(shader_str, filter_defines);
+
+ MEM_freeN(shader_str);
+
+ ds_frag = BLI_dynstr_new();
+ BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_lightprobe_filter_visibility_frag_glsl);
+ shader_str = BLI_dynstr_get_cstring(ds_frag);
+ BLI_dynstr_free(ds_frag);
+
+ e_data.probe_filter_visibility_sh = DRW_shader_create_fullscreen(shader_str, filter_defines);
- ds_frag = BLI_dynstr_new();
- BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_lightprobe_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_lightprobe_cube_display_frag_glsl);
- shader_str = BLI_dynstr_get_cstring(ds_frag);
- BLI_dynstr_free(ds_frag);
+ MEM_freeN(shader_str);
- e_data.probe_cube_display_sh = DRW_shader_create(
- datatoc_lightprobe_cube_display_vert_glsl, NULL, shader_str, NULL);
+ ds_frag = BLI_dynstr_new();
+ BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_irradiance_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_lightprobe_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_lightprobe_grid_display_frag_glsl);
+ shader_str = BLI_dynstr_get_cstring(ds_frag);
+ BLI_dynstr_free(ds_frag);
- MEM_freeN(shader_str);
+ e_data.probe_grid_display_sh = DRW_shader_create(
+ datatoc_lightprobe_grid_display_vert_glsl, NULL, shader_str, filter_defines);
- e_data.probe_planar_display_sh = DRW_shader_create(
- datatoc_lightprobe_planar_display_vert_glsl, NULL,
- datatoc_lightprobe_planar_display_frag_glsl, NULL);
+ MEM_freeN(shader_str);
- e_data.probe_planar_downsample_sh = DRW_shader_create(
- datatoc_lightprobe_planar_downsample_vert_glsl,
- datatoc_lightprobe_planar_downsample_geom_glsl,
- datatoc_lightprobe_planar_downsample_frag_glsl,
- NULL);
+ e_data.probe_grid_fill_sh = DRW_shader_create_fullscreen(
+ datatoc_lightprobe_grid_fill_frag_glsl, filter_defines);
- e_data.hammersley = create_hammersley_sample_texture(1024);
+ ds_frag = BLI_dynstr_new();
+ BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_lightprobe_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_lightprobe_cube_display_frag_glsl);
+ shader_str = BLI_dynstr_get_cstring(ds_frag);
+ BLI_dynstr_free(ds_frag);
+
+ e_data.probe_cube_display_sh = DRW_shader_create(
+ datatoc_lightprobe_cube_display_vert_glsl, NULL, shader_str, NULL);
+
+ MEM_freeN(shader_str);
+
+ e_data.probe_planar_display_sh = DRW_shader_create(
+ datatoc_lightprobe_planar_display_vert_glsl, NULL,
+ datatoc_lightprobe_planar_display_frag_glsl, NULL);
+
+ e_data.probe_planar_downsample_sh = DRW_shader_create(
+ datatoc_lightprobe_planar_downsample_vert_glsl,
+ datatoc_lightprobe_planar_downsample_geom_glsl,
+ datatoc_lightprobe_planar_downsample_frag_glsl,
+ NULL);
+
+ e_data.hammersley = create_hammersley_sample_texture(HAMMERSLEY_SIZE);
+}
+
+void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(vedata))
+{
+ bool update_all = false;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ViewLayer *view_layer = draw_ctx->view_layer;
+ IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE);
+
+ /* Shaders */
+ if (!e_data.probe_filter_glossy_sh) {
+ lightprobe_shaders_init();
}
if (!sldata->probes) {
@@ -275,21 +308,15 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(veda
}
int prop_bounce_num = BKE_collection_engine_property_value_get_int(props, "gi_diffuse_bounces");
- /* Update all probes if number of bounces mismatch. */
if (sldata->probes->num_bounce != prop_bounce_num) {
- e_data.update_world |= PROBE_UPDATE_ALL;
- sldata->probes->updated_bounce = 0;
- sldata->probes->grid_initialized = false;
+ sldata->probes->num_bounce = prop_bounce_num;
+ update_all = true;
}
- sldata->probes->num_bounce = prop_bounce_num;
int prop_cubemap_res = BKE_collection_engine_property_value_get_int(props, "gi_cubemap_resolution");
if (sldata->probes->cubemap_res != prop_cubemap_res) {
sldata->probes->cubemap_res = prop_cubemap_res;
-
- e_data.update_world |= PROBE_UPDATE_ALL;
- sldata->probes->updated_bounce = 0;
- sldata->probes->grid_initialized = false;
+ update_all = true;
sldata->probes->target_size = prop_cubemap_res >> 1;
@@ -297,25 +324,27 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(veda
DRW_TEXTURE_FREE_SAFE(sldata->probe_pool);
}
- /* Setup Render Target Cubemap */
-
- /* We do this detach / attach dance to not generate an invalid framebuffer (mixed cubemap / 2D map) */
- if (sldata->probe_rt) {
- /* XXX Silly,TODO Cleanup this mess */
- DRW_framebuffer_texture_detach(sldata->probe_rt);
+ int visibility_res = BKE_collection_engine_property_value_get_int(props, "gi_visibility_resolution");
+ if (sldata->probes->irradiance_vis_size != visibility_res) {
+ sldata->probes->irradiance_vis_size = visibility_res;
+ update_all = true;
}
- DRWFboTexture tex_probe = {&e_data.cube_face_depth, DRW_TEX_DEPTH_24, DRW_TEX_TEMP};
- DRW_framebuffer_init(&sldata->probe_fb, &draw_engine_eevee_type, sldata->probes->target_size, sldata->probes->target_size, &tex_probe, 1);
+ if (update_all) {
+ e_data.update_world |= PROBE_UPDATE_ALL;
+ sldata->probes->updated_bounce = 0;
+ sldata->probes->grid_initialized = false;
+ }
+ /* Setup Render Target Cubemap */
if (!sldata->probe_rt) {
+ sldata->probe_depth_rt = DRW_texture_create_cube(sldata->probes->target_size, DRW_TEX_DEPTH_24, 0, NULL);
sldata->probe_rt = DRW_texture_create_cube(sldata->probes->target_size, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL);
}
- if (sldata->probe_rt) {
- /* XXX Silly,TODO Cleanup this mess */
- DRW_framebuffer_texture_attach(sldata->probe_fb, sldata->probe_rt, 0, 0);
- }
+ DRWFboTexture tex_probe[2] = {{&sldata->probe_depth_rt, DRW_TEX_DEPTH_24, 0},
+ {&sldata->probe_rt, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP}};
+ DRW_framebuffer_init(&sldata->probe_fb, &draw_engine_eevee_type, sldata->probes->target_size, sldata->probes->target_size, tex_probe, 2);
/* Minmaxz Pyramid */
// DRWFboTexture tex_minmaxz = {&e_data.cube_face_minmaxz, DRW_TEX_RG_32, DRW_TEX_MIPMAP | DRW_TEX_TEMP};
@@ -344,6 +373,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
pinfo->num_cube = 1; /* at least one for the world */
pinfo->num_grid = 1;
pinfo->num_planar = 0;
+ pinfo->total_irradiance_samples = 1;
memset(pinfo->probes_cube_ref, 0, sizeof(pinfo->probes_cube_ref));
memset(pinfo->probes_grid_ref, 0, sizeof(pinfo->probes_grid_ref));
memset(pinfo->probes_planar_ref, 0, sizeof(pinfo->probes_planar_ref));
@@ -435,10 +465,29 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat
}
{
+ psl->probe_visibility_compute = DRW_pass_create("LightProbe Visibility Compute", DRW_STATE_WRITE_COLOR);
+
+ DRWShadingGroup *grp = DRW_shgroup_create(e_data.probe_filter_visibility_sh, psl->probe_visibility_compute);
+ DRW_shgroup_uniform_int(grp, "outputSize", &sldata->probes->shres, 1);
+ DRW_shgroup_uniform_float(grp, "visibilityRange", &sldata->probes->visibility_range, 1);
+ DRW_shgroup_uniform_float(grp, "visibilityBlur", &sldata->probes->visibility_blur, 1);
+ DRW_shgroup_uniform_float(grp, "sampleCount", &sldata->probes->samples_ct, 1);
+ DRW_shgroup_uniform_float(grp, "invSampleCount", &sldata->probes->invsamples_ct, 1);
+ DRW_shgroup_uniform_float(grp, "storedTexelSize", &sldata->probes->texel_size, 1);
+ DRW_shgroup_uniform_float(grp, "nearClip", &sldata->probes->near_clip, 1);
+ DRW_shgroup_uniform_float(grp, "farClip", &sldata->probes->far_clip, 1);
+ DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley);
+ DRW_shgroup_uniform_texture(grp, "probeDepth", sldata->probe_depth_rt);
+
+ struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get();
+ DRW_shgroup_call_add(grp, geom, NULL);
+ }
+
+ {
psl->probe_grid_fill = DRW_pass_create("LightProbe Grid Floodfill", DRW_STATE_WRITE_COLOR);
DRWShadingGroup *grp = DRW_shgroup_create(e_data.probe_grid_fill_sh, psl->probe_grid_fill);
- DRW_shgroup_uniform_buffer(grp, "gridTexture", &sldata->irradiance_pool);
+ DRW_shgroup_uniform_buffer(grp, "irradianceGrid", &sldata->irradiance_pool);
struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get();
DRW_shgroup_call_add(grp, geom, NULL);
@@ -486,11 +535,20 @@ void EEVEE_lightprobes_cache_add(EEVEE_ViewLayerData *sldata, Object *ob)
return;
}
- EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob);
+ EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob);
ped->num_cell = probe->grid_resolution_x * probe->grid_resolution_y * probe->grid_resolution_z;
- if ((ob->deg_update_flag & DEG_RUNTIME_DATA_UPDATE) != 0) {
+ if ((probe->type == LIGHTPROBE_TYPE_GRID) &&
+ ((pinfo->total_irradiance_samples + ped->num_cell) >= MAX_IRRADIANCE_SAMPLES))
+ {
+ printf("Too much grid samples !!!\n");
+ return;
+ }
+
+ if (ped->need_full_update) {
+ ped->need_full_update = false;
+
ped->need_update = true;
ped->probe_id = 0;
@@ -520,6 +578,7 @@ void EEVEE_lightprobes_cache_add(EEVEE_ViewLayerData *sldata, Object *ob)
else { /* GRID */
pinfo->probes_grid_ref[pinfo->num_grid] = ob;
pinfo->num_grid++;
+ pinfo->total_irradiance_samples += ped->num_cell;
}
}
@@ -549,7 +608,7 @@ static void EEVEE_planar_reflections_updates(EEVEE_ViewLayerData *sldata, EEVEE_
for (int i = 0; (ob = pinfo->probes_planar_ref[i]) && (i < MAX_PLANAR); i++) {
LightProbe *probe = (LightProbe *)ob->data;
EEVEE_PlanarReflection *eplanar = &pinfo->planar_data[i];
- EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob);
+ EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob);
/* Computing mtx : matrix that mirror position around object's XY plane. */
normalize_m4_m4(normat, ob->obmat); /* object > world */
@@ -644,7 +703,7 @@ static void EEVEE_lightprobes_updates(EEVEE_ViewLayerData *sldata, EEVEE_PassLis
for (int i = 1; (ob = pinfo->probes_cube_ref[i]) && (i < MAX_PROBE); i++) {
LightProbe *probe = (LightProbe *)ob->data;
EEVEE_LightProbe *eprobe = &pinfo->probe_data[i];
- EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob);
+ EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob);
/* Update transforms */
copy_v3_v3(eprobe->position, ob->obmat[3]);
@@ -690,7 +749,14 @@ static void EEVEE_lightprobes_updates(EEVEE_ViewLayerData *sldata, EEVEE_PassLis
for (int i = 1; (ob = pinfo->probes_grid_ref[i]) && (i < MAX_GRID); i++) {
LightProbe *probe = (LightProbe *)ob->data;
EEVEE_LightGrid *egrid = &pinfo->grid_data[i];
- EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob);
+ EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob);
+
+ /* If one grid has move we need to recompute all the lighting. */
+ if (!pinfo->grid_initialized) {
+ ped->updated_cells = 0;
+ ped->updated_lvl = 0;
+ ped->need_update = true;
+ }
/* Add one for level 0 */
ped->max_lvl = 1.0f + floorf(log2f((float)MAX3(probe->grid_resolution_x,
@@ -742,6 +808,13 @@ static void EEVEE_lightprobes_updates(EEVEE_ViewLayerData *sldata, EEVEE_PassLis
copy_v3_v3_int(egrid->resolution, &probe->grid_resolution_x);
+ /* Visibility bias */
+ egrid->visibility_bias = 0.05f * probe->vis_bias;
+ egrid->visibility_bleed = probe->vis_bleedbias;
+ egrid->visibility_range = max_ff(max_ff(len_v3(egrid->increment_x),
+ len_v3(egrid->increment_y)),
+ len_v3(egrid->increment_z)) + 1.0f;
+
/* Debug Display */
if (BKE_object_is_visible(ob) &&
DRW_state_draw_support() &&
@@ -780,6 +853,18 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved
pinfo->cache_num_planar = pinfo->num_planar;
}
+ int irr_size[3];
+ irradiance_pool_size_get(pinfo->irradiance_vis_size, pinfo->total_irradiance_samples, irr_size);
+
+ if ((irr_size[0] != pinfo->cache_irradiance_size[0]) ||
+ (irr_size[1] != pinfo->cache_irradiance_size[1]) ||
+ (irr_size[2] != pinfo->cache_irradiance_size[2]))
+ {
+ DRW_TEXTURE_FREE_SAFE(sldata->irradiance_pool);
+ DRW_TEXTURE_FREE_SAFE(sldata->irradiance_rt);
+ copy_v3_v3_int(pinfo->cache_irradiance_size, irr_size);
+ }
+
/* XXX this should be run each frame as it ensure planar_depth is set */
planar_pool_ensure_alloc(vedata, pinfo->num_planar);
@@ -800,7 +885,7 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved
pinfo->cache_num_cube = pinfo->num_cube;
for (int i = 1; (ob = pinfo->probes_cube_ref[i]) && (i < MAX_PROBE); i++) {
- EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob);
+ EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob);
ped->need_update = true;
ped->ready_to_shade = false;
ped->probe_id = 0;
@@ -816,16 +901,17 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved
/* we need a signed format for Spherical Harmonics */
int irradiance_format = DRW_TEX_RGBA_16;
#else
- int irradiance_format = DRW_TEX_RGB_11_11_10;
+ int irradiance_format = DRW_TEX_RGBA_8;
#endif
- /* TODO Allocate bigger storage if needed. */
if (!sldata->irradiance_pool || !sldata->irradiance_rt) {
if (!sldata->irradiance_pool) {
- sldata->irradiance_pool = DRW_texture_create_2D(IRRADIANCE_POOL_SIZE, IRRADIANCE_POOL_SIZE, irradiance_format, DRW_TEX_FILTER, NULL);
+ sldata->irradiance_pool = DRW_texture_create_2D_array(irr_size[0], irr_size[1], irr_size[2],
+ irradiance_format, DRW_TEX_FILTER, NULL);
}
if (!sldata->irradiance_rt) {
- sldata->irradiance_rt = DRW_texture_create_2D(IRRADIANCE_POOL_SIZE, IRRADIANCE_POOL_SIZE, irradiance_format, DRW_TEX_FILTER, NULL);
+ sldata->irradiance_rt = DRW_texture_create_2D_array(irr_size[0], irr_size[1], irr_size[2],
+ irradiance_format, DRW_TEX_FILTER, NULL);
}
pinfo->num_render_grid = 0;
pinfo->updated_bounce = 0;
@@ -833,7 +919,7 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved
e_data.update_world |= PROBE_UPDATE_GRID;
for (int i = 1; (ob = pinfo->probes_grid_ref[i]) && (i < MAX_PROBE); i++) {
- EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob);
+ EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob);
ped->need_update = true;
ped->updated_cells = 0;
}
@@ -944,10 +1030,15 @@ static void glossy_filter_probe(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata,
}
/* Diffuse filter probe_rt to irradiance_pool at index probe_idx */
-static void diffuse_filter_probe(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, EEVEE_PassList *psl, int offset)
+static void diffuse_filter_probe(
+ EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, EEVEE_PassList *psl, int offset,
+ float clipsta, float clipend, float vis_range, float vis_blur)
{
EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ int pool_size[3];
+ irradiance_pool_size_get(pinfo->irradiance_vis_size, pinfo->total_irradiance_samples, pool_size);
+
/* find cell position on the virtual 3D texture */
/* NOTE : Keep in sync with load_irradiance_cell() */
#if defined(IRRADIANCE_SH_L2)
@@ -960,7 +1051,7 @@ static void diffuse_filter_probe(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata
pinfo->samples_ct = 1024.0f;
#endif
- int cell_per_row = IRRADIANCE_POOL_SIZE / size[0];
+ int cell_per_row = pool_size[0] / size[0];
int x = size[0] * (offset % cell_per_row);
int y = size[1] * (offset / cell_per_row);
@@ -980,11 +1071,36 @@ static void diffuse_filter_probe(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata
EEVEE_downsample_cube_buffer(vedata, sldata->probe_filter_fb, sldata->probe_rt, (int)(pinfo->lod_rt_max));
DRW_framebuffer_texture_detach(sldata->probe_pool);
- DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0);
+ DRW_framebuffer_texture_layer_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0, 0);
DRW_framebuffer_viewport_size(sldata->probe_filter_fb, x, y, size[0], size[1]);
DRW_draw_pass(psl->probe_diffuse_compute);
+ /* World irradiance have no visibility */
+ if (offset > 0) {
+ /* Compute visibility */
+ pinfo->samples_ct = 512.0f; /* TODO refine */
+ pinfo->invsamples_ct = 1.0f / pinfo->samples_ct;
+ pinfo->shres = pinfo->irradiance_vis_size;
+ pinfo->visibility_range = vis_range;
+ pinfo->visibility_blur = vis_blur;
+ pinfo->near_clip = -clipsta;
+ pinfo->far_clip = -clipend;
+ pinfo->texel_size = 1.0f / (float)pinfo->irradiance_vis_size;
+
+ int cell_per_col = pool_size[1] / pinfo->irradiance_vis_size;
+ cell_per_row = pool_size[0] / pinfo->irradiance_vis_size;
+ x = pinfo->irradiance_vis_size * (offset % cell_per_row);
+ y = pinfo->irradiance_vis_size * ((offset / cell_per_row) % cell_per_col);
+ int layer = 1 + ((offset / cell_per_row) / cell_per_col);
+
+ DRW_framebuffer_texture_detach(sldata->irradiance_rt);
+ DRW_framebuffer_texture_layer_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, layer, 0);
+
+ DRW_framebuffer_viewport_size(sldata->probe_filter_fb, x, y, pinfo->irradiance_vis_size, sldata->probes->irradiance_vis_size);
+ DRW_draw_pass(psl->probe_visibility_compute);
+ }
+
/* reattach to have a valid framebuffer. */
DRW_framebuffer_texture_detach(sldata->irradiance_rt);
DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0);
@@ -1035,8 +1151,8 @@ static void render_scene_to_probe(
/* Detach to rebind the right cubeface. */
DRW_framebuffer_bind(sldata->probe_fb);
- DRW_framebuffer_texture_attach(sldata->probe_fb, e_data.cube_face_depth, 0, 0);
DRW_framebuffer_texture_detach(sldata->probe_rt);
+ DRW_framebuffer_texture_detach(sldata->probe_depth_rt);
for (int i = 0; i < 6; ++i) {
float viewmat[4][4], persmat[4][4];
float viewinv[4][4], persinv[4][4];
@@ -1059,6 +1175,7 @@ static void render_scene_to_probe(
EEVEE_draw_shadows(sldata, psl);
DRW_framebuffer_cubeface_attach(sldata->probe_fb, sldata->probe_rt, 0, i, 0);
+ DRW_framebuffer_cubeface_attach(sldata->probe_fb, sldata->probe_depth_rt, 0, i, 0);
DRW_framebuffer_viewport_size(sldata->probe_fb, 0, 0, pinfo->target_size, pinfo->target_size);
DRW_framebuffer_clear(false, true, false, NULL, 1.0);
@@ -1069,7 +1186,7 @@ static void render_scene_to_probe(
DRW_draw_pass(psl->probe_background);
- // EEVEE_create_minmax_buffer(vedata, e_data.cube_face_depth);
+ // EEVEE_create_minmax_buffer(vedata, sldata->probe_depth_rt);
/* Rebind Planar FB */
DRW_framebuffer_bind(sldata->probe_fb);
@@ -1080,9 +1197,10 @@ static void render_scene_to_probe(
DRW_draw_pass(psl->sss_pass); /* Only output standard pass */
DRW_framebuffer_texture_detach(sldata->probe_rt);
+ DRW_framebuffer_texture_detach(sldata->probe_depth_rt);
}
DRW_framebuffer_texture_attach(sldata->probe_fb, sldata->probe_rt, 0, 0);
- DRW_framebuffer_texture_detach(e_data.cube_face_depth);
+ DRW_framebuffer_texture_attach(sldata->probe_fb, sldata->probe_depth_rt, 0, 0);
DRW_viewport_matrix_override_unset(DRW_MAT_PERS);
DRW_viewport_matrix_override_unset(DRW_MAT_PERSINV);
@@ -1203,6 +1321,7 @@ static void render_world_to_probe(EEVEE_ViewLayerData *sldata, EEVEE_PassList *p
/* Detach to rebind the right cubeface. */
DRW_framebuffer_bind(sldata->probe_fb);
DRW_framebuffer_texture_detach(sldata->probe_rt);
+ DRW_framebuffer_texture_detach(sldata->probe_depth_rt);
for (int i = 0; i < 6; ++i) {
float viewmat[4][4], persmat[4][4];
float viewinv[4][4], persinv[4][4];
@@ -1228,6 +1347,7 @@ static void render_world_to_probe(EEVEE_ViewLayerData *sldata, EEVEE_PassList *p
DRW_framebuffer_texture_detach(sldata->probe_rt);
}
DRW_framebuffer_texture_attach(sldata->probe_fb, sldata->probe_rt, 0, 0);
+ DRW_framebuffer_texture_attach(sldata->probe_fb, sldata->probe_depth_rt, 0, 0);
DRW_viewport_matrix_override_unset(DRW_MAT_PERS);
DRW_viewport_matrix_override_unset(DRW_MAT_PERSINV);
@@ -1258,262 +1378,275 @@ static void lightprobe_cell_world_location_get(EEVEE_LightGrid *egrid, float loc
add_v3_v3(r_pos, tmp);
}
-void EEVEE_lightprobes_refresh(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+static void lightprobes_refresh_world(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
{
- EEVEE_TextureList *txl = vedata->txl;
EEVEE_PassList *psl = vedata->psl;
- EEVEE_StorageList *stl = vedata->stl;
EEVEE_LightProbesInfo *pinfo = sldata->probes;
- Object *ob;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- RegionView3D *rv3d = draw_ctx->rv3d;
-
- /* Render world in priority */
- if (e_data.update_world) {
- render_world_to_probe(sldata, psl);
-
- if (e_data.update_world & PROBE_UPDATE_CUBE) {
- glossy_filter_probe(sldata, vedata, psl, 0);
- }
-
- if (e_data.update_world & PROBE_UPDATE_GRID) {
- diffuse_filter_probe(sldata, vedata, psl, 0);
-
- SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt);
-
- DRW_framebuffer_texture_detach(sldata->probe_pool);
+ render_world_to_probe(sldata, psl);
+ if (e_data.update_world & PROBE_UPDATE_CUBE) {
+ glossy_filter_probe(sldata, vedata, psl, 0);
+ }
+ if (e_data.update_world & PROBE_UPDATE_GRID) {
+ diffuse_filter_probe(sldata, vedata, psl, 0, 0.0, 0.0, 0.0, 0.0);
+ SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt);
+ DRW_framebuffer_texture_detach(sldata->probe_pool);
+ DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0);
+ DRW_draw_pass(psl->probe_grid_fill);
+ DRW_framebuffer_texture_detach(sldata->irradiance_rt);
+ DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0);
+ }
+ e_data.update_world = 0;
+ if (!e_data.world_ready_to_shade) {
+ e_data.world_ready_to_shade = true;
+ pinfo->num_render_cube = 1;
+ pinfo->num_render_grid = 1;
+ }
+ DRW_viewport_request_redraw();
+}
- DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0);
- DRW_draw_pass(psl->probe_grid_fill);
- DRW_framebuffer_texture_detach(sldata->irradiance_rt);
+static void lightprobes_refresh_initialize_grid(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ EEVEE_PassList *psl = vedata->psl;
+ if (pinfo->grid_initialized) {
+ /* Grid is already initialized, nothing to do. */
+ return;
+ }
+ DRW_framebuffer_texture_detach(sldata->probe_pool);
+ /* Flood fill with world irradiance. */
+ DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0);
+ DRW_framebuffer_bind(sldata->probe_filter_fb);
+ DRW_draw_pass(psl->probe_grid_fill);
+ DRW_framebuffer_texture_detach(sldata->irradiance_rt);
- DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0);
- }
+ SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt);
+ DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0);
+ DRW_draw_pass(psl->probe_grid_fill);
- e_data.update_world = 0;
+ DRW_framebuffer_texture_detach(sldata->irradiance_rt);
+ SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt);
+ /* Reattach to have a valid framebuffer. */
+ DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0);
+ pinfo->grid_initialized = true;
+}
- if (!e_data.world_ready_to_shade) {
- e_data.world_ready_to_shade = true;
- pinfo->num_render_cube = 1;
- pinfo->num_render_grid = 1;
+static void lightprobes_refresh_planar(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_TextureList *txl = vedata->txl;
+ Object *ob;
+ EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ for (int i = 0; (ob = pinfo->probes_planar_ref[i]) && (i < MAX_PLANAR); i++) {
+ EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob);
+ if (!ped->need_update) {
+ continue;
}
-
- DRW_viewport_request_redraw();
+ /* Temporary Remove all planar reflections (avoid lag effect). */
+ int tmp_num_planar = pinfo->num_planar;
+ pinfo->num_planar = 0;
+ render_scene_to_planar(sldata, vedata, i, ped->viewmat, ped->persmat, ped->planer_eq_offset);
+ /* Restore */
+ pinfo->num_planar = tmp_num_planar;
+ ped->need_update = false;
+ ped->probe_id = i;
}
- else if (true) { /* TODO if at least one probe needs refresh */
+ /* If there is at least one planar probe */
+ if (pinfo->num_planar > 0 && (vedata->stl->effects->enabled_effects & EFFECT_SSR) != 0) {
+ const int max_lod = 9;
+ DRW_stats_group_start("Planar Probe Downsample");
+ DRW_framebuffer_recursive_downsample(vedata->fbl->downsample_fb, txl->planar_pool, max_lod, &downsample_planar, vedata);
+ /* For shading, save max level of the planar map */
+ pinfo->lod_planar_max = (float)(max_lod);
+ DRW_stats_group_end();
+ }
+}
- if (draw_ctx->evil_C != NULL) {
- /* Only compute probes if not navigating or in playback */
- struct wmWindowManager *wm = CTX_wm_manager(draw_ctx->evil_C);
- if (((rv3d->rflag & RV3D_NAVIGATING) != 0) || ED_screen_animation_no_scrub(wm) != NULL) {
- goto update_planar;
- }
+static void lightprobes_refresh_cube(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ Object *ob;
+ for (int i = 1; (ob = pinfo->probes_cube_ref[i]) && (i < MAX_PROBE); i++) {
+ EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob);
+ if (!ped->need_update) {
+ continue;
}
-
- if (!pinfo->grid_initialized) {
- DRW_framebuffer_texture_detach(sldata->probe_pool);
-
- /* Flood fill with world irradiance. */
- DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0);
- DRW_draw_pass(psl->probe_grid_fill);
- DRW_framebuffer_texture_detach(sldata->irradiance_rt);
-
- SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt);
-
- DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0);
- DRW_draw_pass(psl->probe_grid_fill);
- DRW_framebuffer_texture_detach(sldata->irradiance_rt);
-
- SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt);
-
- /* reattach to have a valid framebuffer. */
- DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0);
-
- pinfo->grid_initialized = true;
+ LightProbe *prb = (LightProbe *)ob->data;
+ render_scene_to_probe(sldata, vedata, ob->obmat[3], prb->clipsta, prb->clipend);
+ glossy_filter_probe(sldata, vedata, psl, i);
+ ped->need_update = false;
+ ped->probe_id = i;
+ if (!ped->ready_to_shade) {
+ pinfo->num_render_cube++;
+ ped->ready_to_shade = true;
}
-
- /* Reflection probes depend on diffuse lighting thus on irradiance grid,
- * so update them first. */
- while (pinfo->updated_bounce < pinfo->num_bounce) {
- pinfo->num_render_grid = pinfo->num_grid;
-
- for (int i = 1; (ob = pinfo->probes_grid_ref[i]) && (i < MAX_GRID); i++) {
- EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob);
-
- if (ped->need_update) {
- EEVEE_LightGrid *egrid = &pinfo->grid_data[i];
- LightProbe *prb = (LightProbe *)ob->data;
-
- /* Find the next cell corresponding to the current level. */
- bool valid_cell = false;
- int cell_id = ped->updated_cells;
- float pos[3], grid_loc[3];
-
- /* Other levels */
- int current_stride = 1 << max_ii(0, ped->max_lvl - ped->updated_lvl);
- int prev_stride = current_stride << 1;
-
- while (!valid_cell) {
- cell_id = ped->updated_cells;
- lightprobe_cell_grid_location_get(egrid, cell_id, grid_loc);
-
- if (ped->updated_lvl == 0 && cell_id == 0) {
- valid_cell = true;
- ped->updated_cells = ped->num_cell;
- continue;
- }
- else if (((((int)grid_loc[0] % current_stride) == 0) &&
- (((int)grid_loc[1] % current_stride) == 0) &&
- (((int)grid_loc[2] % current_stride) == 0)) &&
- !((((int)grid_loc[0] % prev_stride) == 0) &&
- (((int)grid_loc[1] % prev_stride) == 0) &&
- (((int)grid_loc[2] % prev_stride) == 0)))
- {
- valid_cell = true;
- }
-
- ped->updated_cells++;
-
- if (ped->updated_cells > ped->num_cell) {
- goto skip_rendering;
- }
- }
-
- lightprobe_cell_world_location_get(egrid, grid_loc, pos);
-
- SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt);
-
- /* Temporary Remove all probes. */
- int tmp_num_render_grid = pinfo->num_render_grid;
- int tmp_num_render_cube = pinfo->num_render_cube;
- int tmp_num_planar = pinfo->num_planar;
- pinfo->num_render_cube = 0;
- pinfo->num_planar = 0;
-
- /* Use light from previous bounce when capturing radiance. */
- if (pinfo->updated_bounce == 0) {
- pinfo->num_render_grid = 0;
- }
-
- render_scene_to_probe(sldata, vedata, pos, prb->clipsta, prb->clipend);
- diffuse_filter_probe(sldata, vedata, psl, egrid->offset + cell_id);
-
- /* To see what is going on. */
- SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt);
-
- /* Restore */
- pinfo->num_render_grid = tmp_num_render_grid;
- pinfo->num_render_cube = tmp_num_render_cube;
- pinfo->num_planar = tmp_num_planar;
-
-skip_rendering:
-
- if (ped->updated_cells >= ped->num_cell) {
- ped->updated_lvl++;
- ped->updated_cells = 0;
-
- if (ped->updated_lvl > ped->max_lvl) {
- ped->need_update = false;
- }
-
- egrid->level_bias = (float)(1 << max_ii(0, ped->max_lvl - ped->updated_lvl + 1));
- DRW_uniformbuffer_update(sldata->grid_ubo, &sldata->probes->grid_data);
- }
#if 0
- printf("Updated Grid %d : cell %d / %d, bounce %d / %d\n",
- i, ped->updated_cells, ped->num_cell, pinfo->updated_bounce + 1, pinfo->num_bounce);
+ printf("Update Cubemap %d\n", i);
#endif
- /* Only do one probe per frame */
- DRW_viewport_request_redraw();
- /* Do not let this frame accumulate. */
- stl->effects->taa_current_sample = 1;
+ DRW_viewport_request_redraw();
+ /* Do not let this frame accumulate. */
+ stl->effects->taa_current_sample = 1;
- goto update_planar;
- }
- }
+ /* Only do one probe per frame */
+ lightprobes_refresh_planar(sldata, vedata);
+ return;
+ }
+}
- pinfo->updated_bounce++;
- pinfo->num_render_grid = pinfo->num_grid;
+static void lightprobes_refresh_all_no_world(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ EEVEE_PassList *psl = vedata->psl;
+ EEVEE_StorageList *stl = vedata->stl;
+ EEVEE_LightProbesInfo *pinfo = sldata->probes;
+ Object *ob;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ RegionView3D *rv3d = draw_ctx->rv3d;
- if (pinfo->updated_bounce < pinfo->num_bounce) {
- /* Retag all grids to update for next bounce */
- for (int i = 1; (ob = pinfo->probes_grid_ref[i]) && (i < MAX_GRID); i++) {
- EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob);
- ped->need_update = true;
- ped->updated_cells = 0;
- ped->updated_lvl = 0;
+ if (draw_ctx->evil_C != NULL) {
+ /* Only compute probes if not navigating or in playback */
+ struct wmWindowManager *wm = CTX_wm_manager(draw_ctx->evil_C);
+ if (((rv3d->rflag & RV3D_NAVIGATING) != 0) || ED_screen_animation_no_scrub(wm) != NULL) {
+ lightprobes_refresh_planar(sldata, vedata);
+ return;
+ }
+ }
+ /* Make sure grid is initialized. */
+ lightprobes_refresh_initialize_grid(sldata, vedata);
+ /* Reflection probes depend on diffuse lighting thus on irradiance grid,
+ * so update them first. */
+ while (pinfo->updated_bounce < pinfo->num_bounce) {
+ pinfo->num_render_grid = pinfo->num_grid;
+ /* TODO(sergey): This logic can be split into smaller functions. */
+ for (int i = 1; (ob = pinfo->probes_grid_ref[i]) && (i < MAX_GRID); i++) {
+ EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob);
+ if (!ped->need_update) {
+ continue;
+ }
+ EEVEE_LightGrid *egrid = &pinfo->grid_data[i];
+ LightProbe *prb = (LightProbe *)ob->data;
+ /* Find the next cell corresponding to the current level. */
+ bool valid_cell = false;
+ int cell_id = ped->updated_cells;
+ float pos[3], grid_loc[3];
+ /* Other levels */
+ int current_stride = 1 << max_ii(0, ped->max_lvl - ped->updated_lvl);
+ int prev_stride = current_stride << 1;
+ bool do_rendering = true;
+ while (!valid_cell) {
+ cell_id = ped->updated_cells;
+ lightprobe_cell_grid_location_get(egrid, cell_id, grid_loc);
+ if (ped->updated_lvl == 0 && cell_id == 0) {
+ valid_cell = true;
+ ped->updated_cells = ped->num_cell;
+ continue;
+ }
+ else if (((((int)grid_loc[0] % current_stride) == 0) &&
+ (((int)grid_loc[1] % current_stride) == 0) &&
+ (((int)grid_loc[2] % current_stride) == 0)) &&
+ !((((int)grid_loc[0] % prev_stride) == 0) &&
+ (((int)grid_loc[1] % prev_stride) == 0) &&
+ (((int)grid_loc[2] % prev_stride) == 0)))
+ {
+ valid_cell = true;
+ }
+ ped->updated_cells++;
+ if (ped->updated_cells > ped->num_cell) {
+ do_rendering = false;
+ break;
}
-
- SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt);
-
- /* Reset the next buffer so we can see the progress. */
- DRW_framebuffer_texture_detach(sldata->probe_pool);
-
- DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0);
- DRW_draw_pass(psl->probe_grid_fill);
- DRW_framebuffer_texture_detach(sldata->irradiance_rt);
-
- DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0);
}
- }
-
- for (int i = 1; (ob = pinfo->probes_cube_ref[i]) && (i < MAX_PROBE); i++) {
- EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob);
-
- if (ped->need_update) {
- LightProbe *prb = (LightProbe *)ob->data;
-
- render_scene_to_probe(sldata, vedata, ob->obmat[3], prb->clipsta, prb->clipend);
- glossy_filter_probe(sldata, vedata, psl, i);
-
- ped->need_update = false;
- ped->probe_id = i;
-
- if (!ped->ready_to_shade) {
- pinfo->num_render_cube++;
- ped->ready_to_shade = true;
+ if (do_rendering) {
+ lightprobe_cell_world_location_get(egrid, grid_loc, pos);
+ SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt);
+ /* Temporary Remove all probes. */
+ int tmp_num_render_grid = pinfo->num_render_grid;
+ int tmp_num_render_cube = pinfo->num_render_cube;
+ int tmp_num_planar = pinfo->num_planar;
+ float tmp_level_bias = egrid->level_bias;
+ pinfo->num_render_cube = 0;
+ pinfo->num_planar = 0;
+ /* Use light from previous bounce when capturing radiance. */
+ if (pinfo->updated_bounce == 0) {
+ /* But not on first bounce. */
+ pinfo->num_render_grid = 0;
+ }
+ else {
+ /* Remove bias */
+ egrid->level_bias = (float)(1 << 0);
+ DRW_uniformbuffer_update(sldata->grid_ubo, &sldata->probes->grid_data);
+ }
+ render_scene_to_probe(sldata, vedata, pos, prb->clipsta, prb->clipend);
+ diffuse_filter_probe(sldata, vedata, psl, egrid->offset + cell_id,
+ prb->clipsta, prb->clipend, egrid->visibility_range, prb->vis_blur);
+ /* To see what is going on. */
+ SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt);
+ /* Restore */
+ pinfo->num_render_cube = tmp_num_render_cube;
+ pinfo->num_planar = tmp_num_planar;
+ if (pinfo->updated_bounce == 0) {
+ pinfo->num_render_grid = tmp_num_render_grid;
+ }
+ else {
+ egrid->level_bias = tmp_level_bias;
+ DRW_uniformbuffer_update(sldata->grid_ubo, &sldata->probes->grid_data);
}
#if 0
- printf("Update Cubemap %d\n", i);
+ printf("Updated Grid %d : cell %d / %d, bounce %d / %d\n",
+ i, cell_id + 1, ped->num_cell, pinfo->updated_bounce + 1, pinfo->num_bounce);
#endif
- DRW_viewport_request_redraw();
- /* Do not let this frame accumulate. */
- stl->effects->taa_current_sample = 1;
-
- /* Only do one probe per frame */
- goto update_planar;
}
+ if (ped->updated_cells >= ped->num_cell) {
+ ped->updated_lvl++;
+ ped->updated_cells = 0;
+ if (ped->updated_lvl > ped->max_lvl) {
+ ped->need_update = false;
+ }
+ egrid->level_bias = (float)(1 << max_ii(0, ped->max_lvl - ped->updated_lvl + 1));
+ DRW_uniformbuffer_update(sldata->grid_ubo, &sldata->probes->grid_data);
+ }
+ /* Only do one probe per frame */
+ DRW_viewport_request_redraw();
+ /* Do not let this frame accumulate. */
+ stl->effects->taa_current_sample = 1;
+ lightprobes_refresh_planar(sldata, vedata);
+ return;
}
- }
-
-update_planar:
-
- for (int i = 0; (ob = pinfo->probes_planar_ref[i]) && (i < MAX_PLANAR); i++) {
- EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob);
-
- if (ped->need_update) {
- /* Temporary Remove all planar reflections (avoid lag effect). */
- int tmp_num_planar = pinfo->num_planar;
- pinfo->num_planar = 0;
-
- render_scene_to_planar(sldata, vedata, i, ped->viewmat, ped->persmat, ped->planer_eq_offset);
- /* Restore */
- pinfo->num_planar = tmp_num_planar;
+ pinfo->updated_bounce++;
+ pinfo->num_render_grid = pinfo->num_grid;
- ped->need_update = false;
- ped->probe_id = i;
+ if (pinfo->updated_bounce < pinfo->num_bounce) {
+ /* Retag all grids to update for next bounce */
+ for (int i = 1; (ob = pinfo->probes_grid_ref[i]) && (i < MAX_GRID); i++) {
+ EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob);
+ ped->need_update = true;
+ ped->updated_cells = 0;
+ ped->updated_lvl = 0;
+ }
+ /* Reset the next buffer so we can see the progress. */
+ /* irradiance_rt is already the next rt because of the previous SWAP */
+ DRW_framebuffer_texture_detach(sldata->probe_pool);
+ DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0);
+ DRW_framebuffer_bind(sldata->probe_filter_fb);
+ DRW_draw_pass(psl->probe_grid_fill);
+ DRW_framebuffer_texture_detach(sldata->irradiance_rt);
+ DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0);
+ /* Swap AFTER */
+ SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt);
}
}
+ /* Refresh cube probe when needed. */
+ lightprobes_refresh_cube(sldata, vedata);
+}
- /* If there is at least one planar probe */
- if (pinfo->num_planar > 0 && (vedata->stl->effects->enabled_effects & EFFECT_SSR) != 0) {
- const int max_lod = 9;
- DRW_stats_group_start("Planar Probe Downsample");
- DRW_framebuffer_recursive_downsample(vedata->fbl->downsample_fb, txl->planar_pool, max_lod, &downsample_planar, vedata);
- /* For shading, save max level of the planar map */
- pinfo->lod_planar_max = (float)(max_lod);
- DRW_stats_group_end();
+void EEVEE_lightprobes_refresh(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
+{
+ /* Render world in priority */
+ if (e_data.update_world) {
+ lightprobes_refresh_world(sldata, vedata);
+ }
+ else if (true) { /* TODO if at least one probe needs refresh */
+ lightprobes_refresh_all_no_world(sldata, vedata);
}
}
@@ -1522,6 +1655,7 @@ void EEVEE_lightprobes_free(void)
DRW_SHADER_FREE_SAFE(e_data.probe_default_sh);
DRW_SHADER_FREE_SAFE(e_data.probe_filter_glossy_sh);
DRW_SHADER_FREE_SAFE(e_data.probe_filter_diffuse_sh);
+ DRW_SHADER_FREE_SAFE(e_data.probe_filter_visibility_sh);
DRW_SHADER_FREE_SAFE(e_data.probe_grid_fill_sh);
DRW_SHADER_FREE_SAFE(e_data.probe_grid_display_sh);
DRW_SHADER_FREE_SAFE(e_data.probe_planar_display_sh);
diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c
index 2293b4208ad..22465c04cfa 100644
--- a/source/blender/draw/engines/eevee/eevee_lights.c
+++ b/source/blender/draw/engines/eevee/eevee_lights.c
@@ -255,11 +255,7 @@ void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, Object *ob)
}
else {
Lamp *la = (Lamp *)ob->data;
- EEVEE_LampEngineData *led = EEVEE_lamp_data_get(ob);
-
- if ((ob->deg_update_flag & DEG_RUNTIME_DATA_UPDATE) != 0) {
- led->need_update = true;
- }
+ EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(ob);
MEM_SAFE_FREE(led->storage);
@@ -834,7 +830,7 @@ static void delete_pruned_shadowcaster(EEVEE_LampEngineData *led)
static void light_tag_shadow_update(Object *lamp, Object *ob)
{
Lamp *la = lamp->data;
- EEVEE_LampEngineData *led = EEVEE_lamp_data_get(lamp);
+ EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(lamp);
bool is_inside_range = cube_bbox_intersect(lamp->obmat[3], la->clipend, BKE_object_boundbox_get(ob), ob->obmat);
ShadowCaster *ldata = search_object_in_list(&led->shadow_caster_list, ob);
@@ -848,7 +844,7 @@ static void light_tag_shadow_update(Object *lamp, Object *ob)
led->need_update = true;
}
else {
- EEVEE_ObjectEngineData *oedata = EEVEE_object_data_get(ob);
+ EEVEE_ObjectEngineData *oedata = EEVEE_object_data_ensure(ob);
if (oedata->need_update) {
led->need_update = true;
}
@@ -872,6 +868,8 @@ static void eevee_lights_shcaster_updated(EEVEE_ViewLayerData *sldata, Object *o
for (int i = 0; (lamp = linfo->shadow_cube_ref[i]) && (i < MAX_SHADOW_CUBE); i++) {
light_tag_shadow_update(lamp, ob);
}
+ EEVEE_ObjectEngineData *oedata = EEVEE_object_data_ensure(ob);
+ oedata->need_update = false;
}
void EEVEE_lights_update(EEVEE_ViewLayerData *sldata)
@@ -883,7 +881,7 @@ void EEVEE_lights_update(EEVEE_ViewLayerData *sldata)
/* Prune shadow casters to remove if object does not exists anymore (unprune them if object exists) */
Object *lamp;
for (i = 0; (lamp = linfo->shadow_cube_ref[i]) && (i < MAX_SHADOW_CUBE); i++) {
- EEVEE_LampEngineData *led = EEVEE_lamp_data_get(lamp);
+ EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(lamp);
if ((linfo->update_flag & LIGHT_UPDATE_SHADOW_CUBE) != 0) {
led->need_update = true;
@@ -899,12 +897,12 @@ void EEVEE_lights_update(EEVEE_ViewLayerData *sldata)
}
for (i = 0; (ob = linfo->light_ref[i]) && (i < MAX_LIGHT); i++) {
- EEVEE_LampEngineData *led = EEVEE_lamp_data_get(ob);
+ EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(ob);
eevee_light_setup(ob, linfo, led);
}
for (i = 0; (ob = linfo->shadow_cube_ref[i]) && (i < MAX_SHADOW_CUBE); i++) {
- EEVEE_LampEngineData *led = EEVEE_lamp_data_get(ob);
+ EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(ob);
eevee_shadow_cube_setup(ob, linfo, led);
delete_pruned_shadowcaster(led);
}
@@ -923,80 +921,82 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl)
DRW_framebuffer_texture_attach(sldata->shadow_target_fb, sldata->shadow_cube_target, 0, 0);
/* Render each shadow to one layer of the array */
for (i = 0; (ob = linfo->shadow_cube_ref[i]) && (i < MAX_SHADOW_CUBE); i++) {
- EEVEE_LampEngineData *led = EEVEE_lamp_data_get(ob);
+ EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(ob);
Lamp *la = (Lamp *)ob->data;
float cube_projmat[4][4];
perspective_m4(cube_projmat, -la->clipsta, la->clipsta, -la->clipsta, la->clipsta, la->clipsta, la->clipend);
- if (led->need_update) {
- EEVEE_ShadowRender *srd = &linfo->shadow_render_data;
- EEVEE_ShadowCubeData *evscd = (EEVEE_ShadowCubeData *)led->storage;
+ if (!led->need_update) {
+ continue;
+ }
- srd->clip_near = la->clipsta;
- srd->clip_far = la->clipend;
- copy_v3_v3(srd->position, ob->obmat[3]);
- for (int j = 0; j < 6; j++) {
- float tmp[4][4];
+ EEVEE_ShadowRender *srd = &linfo->shadow_render_data;
+ EEVEE_ShadowCubeData *evscd = (EEVEE_ShadowCubeData *)led->storage;
- unit_m4(tmp);
- negate_v3_v3(tmp[3], ob->obmat[3]);
- mul_m4_m4m4(srd->viewmat[j], cubefacemat[j], tmp);
+ srd->clip_near = la->clipsta;
+ srd->clip_far = la->clipend;
+ copy_v3_v3(srd->position, ob->obmat[3]);
+ for (int j = 0; j < 6; j++) {
+ float tmp[4][4];
- mul_m4_m4m4(srd->shadowmat[j], cube_projmat, srd->viewmat[j]);
- }
- DRW_uniformbuffer_update(sldata->shadow_render_ubo, srd);
-
- DRW_framebuffer_bind(sldata->shadow_target_fb);
- DRW_framebuffer_clear(true, true, false, clear_col, 1.0f);
-
- /* Render shadow cube */
- DRW_draw_pass(psl->shadow_cube_pass);
-
- /* 0.001f is arbitrary, but it should be relatively small so that filter size is not too big. */
- float filter_texture_size = la->soft * 0.001f;
- float filter_pixel_size = ceil(filter_texture_size / linfo->shadow_render_data.cube_texel_size);
- linfo->filter_size = linfo->shadow_render_data.cube_texel_size * ((filter_pixel_size > 1.0f) ? 1.5f : 0.0f);
-
- /* TODO: OPTI: Filter all faces in one/two draw call */
- for (linfo->current_shadow_face = 0;
- linfo->current_shadow_face < 6;
- linfo->current_shadow_face++)
- {
- /* Copy using a small 3x3 box filter */
- DRW_framebuffer_cubeface_attach(sldata->shadow_store_fb, sldata->shadow_cube_blur, 0, linfo->current_shadow_face, 0);
- DRW_framebuffer_bind(sldata->shadow_store_fb);
- DRW_draw_pass(psl->shadow_cube_copy_pass);
- DRW_framebuffer_texture_detach(sldata->shadow_cube_blur);
- }
+ unit_m4(tmp);
+ negate_v3_v3(tmp[3], ob->obmat[3]);
+ mul_m4_m4m4(srd->viewmat[j], cubefacemat[j], tmp);
- /* Push it to shadowmap array */
+ mul_m4_m4m4(srd->shadowmat[j], cube_projmat, srd->viewmat[j]);
+ }
+ DRW_uniformbuffer_update(sldata->shadow_render_ubo, srd);
- /* Adjust constants if concentric samples change. */
- const float max_filter_size = 7.5f;
- const float previous_box_filter_size = 9.0f; /* Dunno why but that works. */
- const int max_sample = 256;
+ DRW_framebuffer_bind(sldata->shadow_target_fb);
+ DRW_framebuffer_clear(true, true, false, clear_col, 1.0f);
- if (filter_pixel_size > 2.0f) {
- linfo->filter_size = linfo->shadow_render_data.cube_texel_size * max_filter_size * previous_box_filter_size;
- filter_pixel_size = max_ff(0.0f, filter_pixel_size - 3.0f);
- /* Compute number of concentric samples. Depends directly on filter size. */
- float pix_size_sqr = filter_pixel_size * filter_pixel_size;
- srd->shadow_samples_ct = min_ii(max_sample, 4 + 8 * (int)filter_pixel_size + 4 * (int)(pix_size_sqr));
- }
- else {
- linfo->filter_size = 0.0f;
- srd->shadow_samples_ct = 4;
- }
- srd->shadow_inv_samples_ct = 1.0f / (float)srd->shadow_samples_ct;
- DRW_uniformbuffer_update(sldata->shadow_render_ubo, srd);
+ /* Render shadow cube */
+ DRW_draw_pass(psl->shadow_cube_pass);
- DRW_framebuffer_texture_layer_attach(sldata->shadow_store_fb, sldata->shadow_pool, 0, evscd->layer_id, 0);
+ /* 0.001f is arbitrary, but it should be relatively small so that filter size is not too big. */
+ float filter_texture_size = la->soft * 0.001f;
+ float filter_pixel_size = ceil(filter_texture_size / linfo->shadow_render_data.cube_texel_size);
+ linfo->filter_size = linfo->shadow_render_data.cube_texel_size * ((filter_pixel_size > 1.0f) ? 1.5f : 0.0f);
+
+ /* TODO: OPTI: Filter all faces in one/two draw call */
+ for (linfo->current_shadow_face = 0;
+ linfo->current_shadow_face < 6;
+ linfo->current_shadow_face++)
+ {
+ /* Copy using a small 3x3 box filter */
+ DRW_framebuffer_cubeface_attach(sldata->shadow_store_fb, sldata->shadow_cube_blur, 0, linfo->current_shadow_face, 0);
DRW_framebuffer_bind(sldata->shadow_store_fb);
- DRW_draw_pass(psl->shadow_cube_store_pass);
+ DRW_draw_pass(psl->shadow_cube_copy_pass);
+ DRW_framebuffer_texture_detach(sldata->shadow_cube_blur);
+ }
+
+ /* Push it to shadowmap array */
+
+ /* Adjust constants if concentric samples change. */
+ const float max_filter_size = 7.5f;
+ const float previous_box_filter_size = 9.0f; /* Dunno why but that works. */
+ const int max_sample = 256;
- led->need_update = false;
+ if (filter_pixel_size > 2.0f) {
+ linfo->filter_size = linfo->shadow_render_data.cube_texel_size * max_filter_size * previous_box_filter_size;
+ filter_pixel_size = max_ff(0.0f, filter_pixel_size - 3.0f);
+ /* Compute number of concentric samples. Depends directly on filter size. */
+ float pix_size_sqr = filter_pixel_size * filter_pixel_size;
+ srd->shadow_samples_ct = min_ii(max_sample, 4 + 8 * (int)filter_pixel_size + 4 * (int)(pix_size_sqr));
}
+ else {
+ linfo->filter_size = 0.0f;
+ srd->shadow_samples_ct = 4;
+ }
+ srd->shadow_inv_samples_ct = 1.0f / (float)srd->shadow_samples_ct;
+ DRW_uniformbuffer_update(sldata->shadow_render_ubo, srd);
+
+ DRW_framebuffer_texture_layer_attach(sldata->shadow_store_fb, sldata->shadow_pool, 0, evscd->layer_id, 0);
+ DRW_framebuffer_bind(sldata->shadow_store_fb);
+ DRW_draw_pass(psl->shadow_cube_store_pass);
+
+ led->need_update = false;
}
linfo->update_flag &= ~LIGHT_UPDATE_SHADOW_CUBE;
@@ -1007,7 +1007,7 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl)
DRW_stats_group_start("Cascaded Shadow Maps");
DRW_framebuffer_texture_attach(sldata->shadow_target_fb, sldata->shadow_cascade_target, 0, 0);
for (i = 0; (ob = linfo->shadow_cascade_ref[i]) && (i < MAX_SHADOW_CASCADE); i++) {
- EEVEE_LampEngineData *led = EEVEE_lamp_data_get(ob);
+ EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(ob);
Lamp *la = (Lamp *)ob->data;
EEVEE_ShadowCascadeData *evscd = (EEVEE_ShadowCascadeData *)led->storage;
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
index 38f2aab4443..c25ab1e7859 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -374,6 +374,7 @@ static void add_standard_uniforms(
DRW_shgroup_uniform_buffer(shgrp, "probeCubes", &sldata->probe_pool);
DRW_shgroup_uniform_buffer(shgrp, "probePlanars", &vedata->txl->planar_pool);
DRW_shgroup_uniform_buffer(shgrp, "irradianceGrid", &sldata->irradiance_pool);
+ DRW_shgroup_uniform_int(shgrp, "irradianceVisibilitySize", &sldata->probes->irradiance_vis_size, 1);
DRW_shgroup_uniform_buffer(shgrp, "shadowTexture", &sldata->shadow_pool);
DRW_shgroup_uniform_int(shgrp, "outputSsrId", ssr_id, 1);
DRW_shgroup_uniform_vec4(shgrp, "aoParameters[0]", &vedata->stl->effects->ao_dist, 2);
@@ -1295,7 +1296,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sld
/* Do not render surface if we are rendering a volume object
* and do not have a surface closure. */
if (use_volume_material &&
- (gpumat_array[i] && !GPU_material_use_domain_surface(gpumat_array[i])))
+ (gpumat_array[i] && !GPU_material_use_domain_surface(gpumat_array[i])))
{
continue;
}
diff --git a/source/blender/draw/engines/eevee/eevee_motion_blur.c b/source/blender/draw/engines/eevee/eevee_motion_blur.c
index 43aaec1b4ba..d5e0a05f9ed 100644
--- a/source/blender/draw/engines/eevee/eevee_motion_blur.c
+++ b/source/blender/draw/engines/eevee/eevee_motion_blur.c
@@ -19,7 +19,7 @@
*
*/
-/** \file eevee_effects.c
+/** \file eevee_motion_blur.c
* \ingroup draw_engine
*
* Gather all screen space effects technique such as Bloom, Motion Blur, DoF, SSAO, SSR, ...
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index 8e754e71506..98fc6d6a6e4 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -47,11 +47,11 @@ extern struct DrawEngineType draw_engine_eevee_type;
#define IRRADIANCE_HL2
#if defined(IRRADIANCE_SH_L2)
-#define SHADER_IRRADIANCE "#define IRRADIANCE_SH_L2\n"
+# define SHADER_IRRADIANCE "#define IRRADIANCE_SH_L2\n"
#elif defined(IRRADIANCE_CUBEMAP)
-#define SHADER_IRRADIANCE "#define IRRADIANCE_CUBEMAP\n"
+# define SHADER_IRRADIANCE "#define IRRADIANCE_CUBEMAP\n"
#elif defined(IRRADIANCE_HL2)
-#define SHADER_IRRADIANCE "#define IRRADIANCE_HL2\n"
+# define SHADER_IRRADIANCE "#define IRRADIANCE_HL2\n"
#endif
#define SHADER_DEFINES \
@@ -141,6 +141,7 @@ typedef struct EEVEE_PassList {
struct DRWPass *probe_background;
struct DRWPass *probe_glossy_compute;
struct DRWPass *probe_diffuse_compute;
+ struct DRWPass *probe_visibility_compute;
struct DRWPass *probe_grid_fill;
struct DRWPass *probe_display;
struct DRWPass *probe_planar_downsample_ps;
@@ -369,6 +370,7 @@ typedef struct EEVEE_LightGrid {
float increment_x[3], attenuation_bias; /* world space vector between 2 opposite cells */
float increment_y[3], level_bias;
float increment_z[3], pad4;
+ float visibility_bias, visibility_bleed, visibility_range, pad5;
} EEVEE_LightGrid;
typedef struct EEVEE_PlanarReflection {
@@ -386,11 +388,14 @@ typedef struct EEVEE_LightProbesInfo {
int num_cube, cache_num_cube;
int num_grid, cache_num_grid;
int num_planar, cache_num_planar;
+ int total_irradiance_samples; /* Total for all grids */
+ int cache_irradiance_size[3];
int update_flag;
int updated_bounce;
int num_bounce;
int cubemap_res;
int target_size;
+ int irradiance_vis_size;
int grid_initialized;
/* Actual number of probes that have datas. */
int num_render_cube;
@@ -402,9 +407,13 @@ typedef struct EEVEE_LightProbesInfo {
float padding_size;
float samples_ct;
float invsamples_ct;
+ float near_clip;
+ float far_clip;
float roughness;
float lodfactor;
float lod_rt_max, lod_cube_max, lod_planar_max;
+ float visibility_range;
+ float visibility_blur;
int shres;
int shnbr;
bool specular_toggle;
@@ -550,6 +559,7 @@ typedef struct EEVEE_ViewLayerData {
struct GPUFrameBuffer *probe_filter_fb;
struct GPUTexture *probe_rt;
+ struct GPUTexture *probe_depth_rt;
struct GPUTexture *probe_pool;
struct GPUTexture *irradiance_pool;
struct GPUTexture *irradiance_rt;
@@ -568,7 +578,19 @@ typedef struct EEVEE_LampEngineData {
} EEVEE_LampEngineData;
typedef struct EEVEE_LightProbeEngineData {
+ /* NOTE: need_full_update is set by dependency graph when the probe or it's
+ * object is updated. This triggers full probe update, including it's
+ * "progressive" GI refresh.
+ *
+ * need_update is always set to truth when need_full_update is tagged, but
+ * might also be forced to be kept truth during GI refresh stages.
+ *
+ * TODO(sergey): Is there a way to avoid two flags here, or at least make
+ * it more clear what's going on here?
+ */
+ bool need_full_update;
bool need_update;
+
bool ready_to_shade;
int updated_cells;
int updated_lvl;
@@ -629,9 +651,13 @@ typedef struct EEVEE_PrivateData {
/* eevee_data.c */
EEVEE_ViewLayerData *EEVEE_view_layer_data_get(void);
+EEVEE_ViewLayerData *EEVEE_view_layer_data_ensure(void);
EEVEE_ObjectEngineData *EEVEE_object_data_get(Object *ob);
+EEVEE_ObjectEngineData *EEVEE_object_data_ensure(Object *ob);
EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_get(Object *ob);
+EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_ensure(Object *ob);
EEVEE_LampEngineData *EEVEE_lamp_data_get(Object *ob);
+EEVEE_LampEngineData *EEVEE_lamp_data_ensure(Object *ob);
/* eevee_materials.c */
struct GPUTexture *EEVEE_materials_get_util_tex(void); /* XXX */
diff --git a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c
index 72b8c85b7a7..5faac4c42cc 100644
--- a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c
+++ b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c
@@ -56,9 +56,9 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data
IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE);
if (BKE_collection_engine_property_value_get_int(props, "taa_samples") != 1 &&
- /* FIXME the motion blur camera evaluation is tagging view_updated
- * thus making the TAA always reset and never stopping rendering. */
- (effects->enabled_effects & EFFECT_MOTION_BLUR) == 0)
+ /* FIXME the motion blur camera evaluation is tagging view_updated
+ * thus making the TAA always reset and never stopping rendering. */
+ (effects->enabled_effects & EFFECT_MOTION_BLUR) == 0)
{
const float *viewport_size = DRW_viewport_size_get();
float persmat[4][4], viewmat[4][4];
diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c
index 14383e28cc7..dae4503dc32 100644
--- a/source/blender/draw/engines/eevee/eevee_volumes.c
+++ b/source/blender/draw/engines/eevee/eevee_volumes.c
@@ -19,7 +19,7 @@
*
*/
-/** \file eevee_volume.c
+/** \file eevee_volumes.c
* \ingroup draw_engine
*
* Volumetric effects rendering using frostbite approach.
@@ -86,8 +86,8 @@ static void eevee_create_shader_volumes(void)
ds_frag = BLI_dynstr_new();
BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
BLI_dynstr_append(ds_frag, datatoc_bsdf_direct_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_irradiance_lib_glsl);
BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_irradiance_lib_glsl);
BLI_dynstr_append(ds_frag, datatoc_lamps_lib_glsl);
BLI_dynstr_append(ds_frag, datatoc_volumetric_lib_glsl);
e_data.volumetric_common_lamps_lib = BLI_dynstr_get_cstring(ds_frag);
diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
index aecb1e6dde4..37ed2235c6f 100644
--- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
@@ -432,6 +432,78 @@ vec3 normal_decode(vec2 enc, vec3 view)
return n;
}
+/* ---- RGBM (shared multiplier) encoding ---- */
+/* From http://iwasbeingirony.blogspot.fr/2010/06/difference-between-rgbm-and-rgbd.html */
+
+/* Higher RGBM_MAX_RANGE gives imprecision issues in low intensity. */
+#define RGBM_MAX_RANGE 512.0
+
+vec4 rgbm_encode(vec3 rgb)
+{
+ float maxRGB = max_v3(rgb);
+ float M = maxRGB / RGBM_MAX_RANGE;
+ M = ceil(M * 255.0) / 255.0;
+ return vec4(rgb / (M * RGBM_MAX_RANGE), M);
+}
+
+vec3 rgbm_decode(vec4 data)
+{
+ return data.rgb * (data.a * RGBM_MAX_RANGE);
+}
+
+/* ---- RGBE (shared exponent) encoding ---- */
+vec4 rgbe_encode(vec3 rgb)
+{
+ float maxRGB = max_v3(rgb);
+ float fexp = ceil(log2(maxRGB));
+ return vec4(rgb / exp2(fexp), (fexp + 128.0) / 255.0);
+}
+
+vec3 rgbe_decode(vec4 data)
+{
+ float fexp = data.a * 255.0 - 128.0;
+ return data.rgb * exp2(fexp);
+}
+
+#if 1
+#define irradiance_encode rgbe_encode
+#define irradiance_decode rgbe_decode
+#else /* No ecoding (when using floating point format) */
+#define irradiance_encode(X) (X).rgbb
+#define irradiance_decode(X) (X).rgb
+#endif
+
+/* Irradiance Visibility Encoding */
+#if 1
+vec4 visibility_encode(vec2 accum, float range)
+{
+ accum /= range;
+
+ vec4 data;
+ data.x = fract(accum.x);
+ data.y = floor(accum.x) / 255.0;
+ data.z = fract(accum.y);
+ data.w = floor(accum.y) / 255.0;
+
+ return data;
+}
+
+vec2 visibility_decode(vec4 data, float range)
+{
+ return (data.xz + data.yw * 255.0) * range;
+}
+#else /* No ecoding (when using floating point format) */
+vec4 visibility_encode(vec2 accum, float range)
+{
+ return accum.xyxy;
+}
+
+vec2 visibility_decode(vec4 data, float range)
+{
+ return data.xy;
+}
+#endif
+
/* Fresnel monochromatic, perfect mirror */
float F_eta(float eta, float cos_theta)
{
diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl
index f58dac6c0a0..13586619fe9 100644
--- a/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl
@@ -54,7 +54,7 @@ vec3 sample_ggx(vec3 rand, float a2)
{
/* Theta is the aperture angle of the cone */
float z = sqrt( (1.0 - rand.x) / ( 1.0 + a2 * rand.x - rand.x ) ); /* cos theta */
- float r = sqrt( 1.0 - z * z ); /* sin theta */
+ float r = sqrt(max(0.0, 1.0f - z*z)); /* sin theta */
float x = r * rand.y;
float y = r * rand.z;
@@ -82,7 +82,21 @@ vec3 sample_hemisphere(float nsample, vec3 N, vec3 T, vec3 B)
vec3 Xi = hammersley_3d(nsample);
float z = Xi.x; /* cos theta */
- float r = sqrt( 1.0f - z*z ); /* sin theta */
+ float r = sqrt(max(0.0, 1.0f - z*z)); /* sin theta */
+ float x = r * Xi.y;
+ float y = r * Xi.z;
+
+ vec3 Ht = vec3(x, y, z);
+
+ return tangent_to_world(Ht, N, T, B);
+}
+
+vec3 sample_cone(float nsample, float angle, vec3 N, vec3 T, vec3 B)
+{
+ vec3 Xi = hammersley_3d(nsample);
+
+ float z = cos(angle * Xi.x); /* cos theta */
+ float r = sqrt(max(0.0, 1.0f - z*z)); /* sin theta */
float x = r * Xi.y;
float y = r * Xi.z;
diff --git a/source/blender/draw/engines/eevee/shaders/default_frag.glsl b/source/blender/draw/engines/eevee/shaders/default_frag.glsl
index 91746a6f082..45c5c88e763 100644
--- a/source/blender/draw/engines/eevee/shaders/default_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/default_frag.glsl
@@ -13,7 +13,7 @@ Closure nodetree_exec(void)
vec3 out_diff, out_spec, ssr_spec;
eevee_closure_default(N, albedo, f0, 0, roughness, 1.0, out_diff, out_spec, ssr_spec);
- Closure result = Closure(out_spec + out_diff, 1.0, vec4(ssr_spec, roughness), normal_encode(normalize(viewNormal), viewCameraVec), 0);
+ Closure result = Closure(out_spec + out_diff * albedo, 1.0, vec4(ssr_spec, roughness), normal_encode(normalize(viewNormal), viewCameraVec), 0);
return result;
}
diff --git a/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl b/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl
index 95e7af41398..76d20486d3d 100644
--- a/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/irradiance_lib.glsl
@@ -1,5 +1,6 @@
-uniform sampler2D irradianceGrid;
+uniform sampler2DArray irradianceGrid;
+uniform int irradianceVisibilitySize;
#define IRRADIANCE_LIB
@@ -36,7 +37,7 @@ IrradianceData load_irradiance_cell(int cell, vec3 N)
uvs += vec2(cell_co) / vec2(textureSize(irradianceGrid, 0));
IrradianceData ir;
- ir.color = texture(irradianceGrid, uvs).rgb;
+ ir.color = texture(irradianceGrid, vec3(uvs, 0.0)).rgb;
#elif defined(IRRADIANCE_SH_L2)
@@ -48,15 +49,15 @@ IrradianceData load_irradiance_cell(int cell, vec3 N)
ivec3 ofs = ivec3(0, 1, 2);
IrradianceData ir;
- ir.shcoefs[0] = texelFetch(irradianceGrid, cell_co + ofs.xx, 0).rgb;
- ir.shcoefs[1] = texelFetch(irradianceGrid, cell_co + ofs.yx, 0).rgb;
- ir.shcoefs[2] = texelFetch(irradianceGrid, cell_co + ofs.zx, 0).rgb;
- ir.shcoefs[3] = texelFetch(irradianceGrid, cell_co + ofs.xy, 0).rgb;
- ir.shcoefs[4] = texelFetch(irradianceGrid, cell_co + ofs.yy, 0).rgb;
- ir.shcoefs[5] = texelFetch(irradianceGrid, cell_co + ofs.zy, 0).rgb;
- ir.shcoefs[6] = texelFetch(irradianceGrid, cell_co + ofs.xz, 0).rgb;
- ir.shcoefs[7] = texelFetch(irradianceGrid, cell_co + ofs.yz, 0).rgb;
- ir.shcoefs[8] = texelFetch(irradianceGrid, cell_co + ofs.zz, 0).rgb;
+ ir.shcoefs[0] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.xx, 0), 0).rgb;
+ ir.shcoefs[1] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.yx, 0), 0).rgb;
+ ir.shcoefs[2] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.zx, 0), 0).rgb;
+ ir.shcoefs[3] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.xy, 0), 0).rgb;
+ ir.shcoefs[4] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.yy, 0), 0).rgb;
+ ir.shcoefs[5] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.zy, 0), 0).rgb;
+ ir.shcoefs[6] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.xz, 0), 0).rgb;
+ ir.shcoefs[7] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.yz, 0), 0).rgb;
+ ir.shcoefs[8] = texelFetch(irradianceGrid, ivec3(cell_co + ofs.zz, 0), 0).rgb;
#else /* defined(IRRADIANCE_HL2) */
@@ -68,15 +69,51 @@ IrradianceData load_irradiance_cell(int cell, vec3 N)
ivec3 is_negative = ivec3(step(0.0, -N));
IrradianceData ir;
- ir.cubesides[0] = texelFetch(irradianceGrid, cell_co + ivec2(0, is_negative.x), 0).rgb;
- ir.cubesides[1] = texelFetch(irradianceGrid, cell_co + ivec2(1, is_negative.y), 0).rgb;
- ir.cubesides[2] = texelFetch(irradianceGrid, cell_co + ivec2(2, is_negative.z), 0).rgb;
+ ir.cubesides[0] = irradiance_decode(texelFetch(irradianceGrid, ivec3(cell_co + ivec2(0, is_negative.x), 0), 0));
+ ir.cubesides[1] = irradiance_decode(texelFetch(irradianceGrid, ivec3(cell_co + ivec2(1, is_negative.y), 0), 0));
+ ir.cubesides[2] = irradiance_decode(texelFetch(irradianceGrid, ivec3(cell_co + ivec2(2, is_negative.z), 0), 0));
#endif
return ir;
}
+float load_visibility_cell(int cell, vec3 L, float dist, float bias, float bleed_bias, float range)
+{
+ /* Keep in sync with diffuse_filter_probe() */
+ ivec2 cell_co = ivec2(irradianceVisibilitySize);
+ ivec2 cell_per_row_col = textureSize(irradianceGrid, 0).xy / irradianceVisibilitySize;
+ cell_co.x *= (cell % cell_per_row_col.x);
+ cell_co.y *= (cell / cell_per_row_col.x) % cell_per_row_col.y;
+ float layer = 1.0 + float((cell / cell_per_row_col.x) / cell_per_row_col.y);
+
+ vec2 texel_size = 1.0 / vec2(textureSize(irradianceGrid, 0).xy);
+ vec2 co = vec2(cell_co) * texel_size;
+
+ vec2 uv = mapping_octahedron(-L, vec2(1.0 / float(irradianceVisibilitySize)));
+ uv *= vec2(irradianceVisibilitySize) * texel_size;
+
+ vec4 data = texture(irradianceGrid, vec3(co + uv, layer));
+
+ /* Decoding compressed data */
+ vec2 moments = visibility_decode(data, range);
+
+ /* Doing chebishev test */
+ float variance = abs(moments.x * moments.x - moments.y);
+ variance = max(variance, bias / 10.0);
+
+ float d = dist - moments.x;
+ float p_max = variance / (variance + d * d);
+
+ /* Increase contrast in the weight by squaring it */
+ p_max *= p_max;
+
+ /* Now reduce light-bleeding by removing the [0, x] tail and linearly rescaling (x, 1] */
+ p_max = clamp((p_max - bleed_bias) / (1.0 - bleed_bias), 0.0, 1.0);
+
+ return (dist <= moments.x) ? 1.0 : p_max;
+}
+
/* http://seblagarde.wordpress.com/2012/01/08/pi-or-not-to-pi-in-game-lighting-equation/ */
vec3 spherical_harmonics_L1(vec3 N, vec3 shcoefs[4])
{
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl
index 0b97548c8df..eb4315c93a3 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_diffuse_frag.glsl
@@ -192,6 +192,6 @@ void main()
}
}
- FragColor = vec4(out_radiance / weight, 1.0);
+ FragColor = irradiance_encode(out_radiance / weight);
#endif
} \ No newline at end of file
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_visibility_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_visibility_frag.glsl
new file mode 100644
index 00000000000..0727e73f507
--- /dev/null
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_visibility_frag.glsl
@@ -0,0 +1,88 @@
+
+uniform samplerCube probeDepth;
+uniform int outputSize;
+uniform float lodFactor;
+uniform float storedTexelSize;
+uniform float lodMax;
+uniform float nearClip;
+uniform float farClip;
+uniform float visibilityRange;
+uniform float visibilityBlur;
+
+out vec4 FragColor;
+
+vec3 octahedral_to_cubemap_proj(vec2 co)
+{
+ co = co * 2.0 - 1.0;
+
+ vec2 abs_co = abs(co);
+ vec3 v = vec3(co, 1.0 - (abs_co.x + abs_co.y));
+
+ if ( abs_co.x + abs_co.y > 1.0 ) {
+ v.xy = (abs(co.yx) - 1.0) * -sign(co.xy);
+ }
+
+ return v;
+}
+
+float linear_depth(float z)
+{
+ return (nearClip * farClip) / (z * (nearClip - farClip) + farClip);
+}
+
+float get_world_distance(float depth, vec3 cos)
+{
+ float is_background = step(1.0, depth);
+ depth = linear_depth(depth);
+ depth += 1e1 * is_background;
+ cos = normalize(abs(cos));
+ float cos_vec = max(cos.x, max(cos.y, cos.z));
+ return depth / cos_vec;
+}
+
+void main()
+{
+ ivec2 texel = ivec2(gl_FragCoord.xy) % ivec2(outputSize);
+
+ vec3 cos;
+
+ cos.xy = (vec2(texel) + 0.5) * storedTexelSize;
+
+ /* add a 2 pixel border to ensure filtering is correct */
+ cos.xy *= 1.0 + storedTexelSize * 2.0;
+ cos.xy -= storedTexelSize;
+
+ float pattern = 1.0;
+
+ /* edge mirroring : only mirror if directly adjacent
+ * (not diagonally adjacent) */
+ vec2 m = abs(cos.xy - 0.5) + 0.5;
+ vec2 f = floor(m);
+ if (f.x - f.y != 0.0) {
+ cos.xy = 1.0 - cos.xy;
+ }
+
+ /* clamp to [0-1] */
+ cos.xy = fract(cos.xy);
+
+ /* get cubemap vector */
+ cos = normalize(octahedral_to_cubemap_proj(cos.xy));
+
+ vec3 T, B;
+ make_orthonormal_basis(cos, T, B); /* Generate tangent space */
+
+ vec2 accum = vec2(0.0);
+
+ for (float i = 0; i < sampleCount; i++) {
+ vec3 sample = sample_cone(i, M_PI_2 * visibilityBlur, cos, T, B);
+ float depth = texture(probeDepth, sample).r;
+ depth = get_world_distance(depth, sample);
+ accum += vec2(depth, depth * depth);
+ }
+
+ accum *= invSampleCount;
+ accum = abs(accum);
+
+ /* Encode to normalized RGBA 8 */
+ FragColor = visibility_encode(accum, visibilityRange);
+} \ No newline at end of file
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_grid_fill_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_grid_fill_frag.glsl
index cea1ca5e7b0..c9e66ceffb2 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_grid_fill_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_grid_fill_frag.glsl
@@ -1,4 +1,4 @@
-uniform sampler2D gridTexture;
+uniform sampler2DArray irradianceGrid;
out vec4 FragColor;
@@ -12,7 +12,7 @@ void main()
const ivec2 data_size = ivec2(3, 2);
#endif
ivec2 coord = ivec2(gl_FragCoord.xy) % data_size;
- FragColor = texelFetch(gridTexture, coord, 0);
+ FragColor = texelFetch(irradianceGrid, ivec3(coord, 0), 0);
if (any(greaterThanEqual(ivec2(gl_FragCoord.xy), data_size))) {
FragColor = vec4(0.0, 0.0, 0.0, 1.0);
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
index 834bacc118b..e914228aded 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
@@ -49,6 +49,7 @@ struct GridData {
vec4 ws_increment_x_atten_bias; /* world space vector between 2 opposite cells */
vec4 ws_increment_y_lvl_bias;
vec4 ws_increment_z;
+ vec4 vis_bias_bleed_range;
};
#define g_corner ws_corner_atten_scale.xyz
@@ -60,6 +61,9 @@ struct GridData {
#define g_increment_z ws_increment_z.xyz
#define g_resolution resolution_offset.xyz
#define g_offset resolution_offset.w
+#define g_vis_bias vis_bias_bleed_range.x
+#define g_vis_bleed vis_bias_bleed_range.y
+#define g_vis_range vis_bias_bleed_range.z
#ifndef MAX_PROBE
#define MAX_PROBE 1
@@ -227,14 +231,18 @@ vec3 probe_evaluate_grid(GridData gd, vec3 W, vec3 N, vec3 localpos)
gd.g_increment_y * cell_cos.y +
gd.g_increment_z * cell_cos.z);
- // vec3 ws_point_to_cell = ws_cell_location - W;
- // vec3 ws_light = normalize(ws_point_to_cell);
+ vec3 ws_point_to_cell = ws_cell_location - W;
+ float ws_dist_point_to_cell = length(ws_point_to_cell);
+ vec3 ws_light = ws_point_to_cell / ws_dist_point_to_cell;
vec3 trilinear = mix(1 - trilinear_weight, trilinear_weight, offset);
float weight = trilinear.x * trilinear.y * trilinear.z;
+ /* Precomputed visibility */
+ weight *= load_visibility_cell(cell, ws_light, ws_dist_point_to_cell, gd.g_vis_bias, gd.g_vis_bleed, gd.g_vis_range);
+
/* Smooth backface test */
- // weight *= sqrt(max(0.002, dot(ws_light, N)));
+ weight *= sqrt(max(0.002, dot(ws_light, N)));
/* Avoid zero weight */
weight = max(0.00001, weight);
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl
index b3f5e8b60ad..1376c53d633 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl
@@ -128,12 +128,16 @@ vec3 light_volume_shadow(LightData ld, vec3 ray_wpos, vec4 l_vector, sampler3D v
#ifdef IRRADIANCE_LIB
vec3 irradiance_volumetric(vec3 wpos)
{
+#ifdef IRRADIANCE_HL2
IrradianceData ir_data = load_irradiance_cell(0, vec3(1.0));
vec3 irradiance = ir_data.cubesides[0] + ir_data.cubesides[1] + ir_data.cubesides[2];
ir_data = load_irradiance_cell(0, vec3(-1.0));
irradiance += ir_data.cubesides[0] + ir_data.cubesides[1] + ir_data.cubesides[2];
irradiance *= 0.16666666; /* 1/6 */
return irradiance;
+#else
+ return vec3(0.0);
+#endif
}
#endif
diff --git a/source/blender/draw/engines/external/external_engine.c b/source/blender/draw/engines/external/external_engine.c
index 76f5b4d9840..851d0ef9eb7 100644
--- a/source/blender/draw/engines/external/external_engine.c
+++ b/source/blender/draw/engines/external/external_engine.c
@@ -96,7 +96,7 @@ typedef struct EXTERNAL_PrivateData {
/* Functions */
-static void EXTERNAL_engine_init(void *UNUSED(vedata))
+static void external_engine_init(void *UNUSED(vedata))
{
/* Depth prepass */
if (!e_data.depth_sh) {
@@ -104,7 +104,7 @@ static void EXTERNAL_engine_init(void *UNUSED(vedata))
}
}
-static void EXTERNAL_cache_init(void *vedata)
+static void external_cache_init(void *vedata)
{
EXTERNAL_PassList *psl = ((EXTERNAL_Data *)vedata)->psl;
EXTERNAL_StorageList *stl = ((EXTERNAL_Data *)vedata)->stl;
@@ -121,7 +121,7 @@ static void EXTERNAL_cache_init(void *vedata)
}
}
-static void EXTERNAL_cache_populate(void *vedata, Object *ob)
+static void external_cache_populate(void *vedata, Object *ob)
{
EXTERNAL_StorageList *stl = ((EXTERNAL_Data *)vedata)->stl;
@@ -135,11 +135,11 @@ static void EXTERNAL_cache_populate(void *vedata, Object *ob)
}
}
-static void EXTERNAL_cache_finish(void *UNUSED(vedata))
+static void external_cache_finish(void *UNUSED(vedata))
{
}
-static void external_draw_scene(void *vedata)
+static void external_draw_scene_do(void *vedata)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
Scene *scene = draw_ctx->scene;
@@ -151,7 +151,7 @@ static void external_draw_scene(void *vedata)
/* Create render engine. */
if (!rv3d->render_engine) {
- RenderEngineType *engine_type = draw_ctx->engine;
+ RenderEngineType *engine_type = draw_ctx->engine_type;
if (!(engine_type->view_update && engine_type->render_to_view)) {
return;
@@ -184,7 +184,7 @@ static void external_draw_scene(void *vedata)
}
}
-static void EXTERNAL_draw_scene(void *vedata)
+static void external_draw_scene(void *vedata)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
EXTERNAL_PassList *psl = ((EXTERNAL_Data *)vedata)->psl;
@@ -193,29 +193,30 @@ static void EXTERNAL_draw_scene(void *vedata)
* OpenGL render is used for quick preview (thumbnails or sequencer preview)
* where using the rendering engine to preview doesn't make so much sense. */
if (draw_ctx->evil_C) {
- external_draw_scene(vedata);
+ external_draw_scene_do(vedata);
}
DRW_draw_pass(psl->depth_pass);
}
-static void EXTERNAL_engine_free(void)
+static void external_engine_free(void)
{
/* All shaders are builtin. */
}
-static const DrawEngineDataSize EXTERNAL_data_size = DRW_VIEWPORT_DATA_SIZE(EXTERNAL_Data);
+static const DrawEngineDataSize external_data_size = DRW_VIEWPORT_DATA_SIZE(EXTERNAL_Data);
DrawEngineType draw_engine_external_type = {
NULL, NULL,
N_("External"),
- &EXTERNAL_data_size,
- &EXTERNAL_engine_init,
- &EXTERNAL_engine_free,
- &EXTERNAL_cache_init,
- &EXTERNAL_cache_populate,
- &EXTERNAL_cache_finish,
+ &external_data_size,
+ &external_engine_init,
+ &external_engine_free,
+ &external_cache_init,
+ &external_cache_populate,
+ &external_cache_finish,
+ NULL,
+ &external_draw_scene,
NULL,
- &EXTERNAL_draw_scene,
NULL,
};
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index 8d89454fa6a..0753dbc7a1a 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -138,6 +138,7 @@ typedef struct DrawEngineType {
void (*draw_scene)(void *vedata);
void (*view_update)(void *vedata);
+ void (*id_update)(void *vedata, struct ID *id);
} DrawEngineType;
#ifndef __DRW_ENGINE_H__
@@ -383,12 +384,14 @@ struct DefaultTextureList *DRW_viewport_texture_list_get(void);
void DRW_viewport_request_redraw(void);
/* ViewLayers */
-void **DRW_view_layer_engine_data_get(DrawEngineType *engine_type, void (*callback)(void *storage));
+void *DRW_view_layer_engine_data_get(DrawEngineType *engine_type);
+void **DRW_view_layer_engine_data_ensure(DrawEngineType *engine_type, void (*callback)(void *storage));
/* Objects */
-void **DRW_object_engine_data_get(
+void *DRW_object_engine_data_get(Object *ob, DrawEngineType *engine_type);
+void **DRW_object_engine_data_ensure(
Object *ob, DrawEngineType *engine_type, void (*callback)(void *storage));
-struct LampEngineData *DRW_lamp_engine_data_get(Object *ob, struct RenderEngineType *engine_type);
+struct LampEngineData *DRW_lamp_engine_data_ensure(Object *ob, struct RenderEngineType *engine_type);
void DRW_lamp_engine_data_free(struct LampEngineData *led);
/* Settings */
@@ -443,7 +446,7 @@ typedef struct DRWContextState {
/* Use 'scene->obedit' for edit-mode */
struct Object *obact; /* 'OBACT' */
- struct RenderEngineType *engine;
+ struct RenderEngineType *engine_type;
/* Last resort (some functions take this as an arg so we can't easily avoid).
* May be NULL when used for selection or depth buffer. */
diff --git a/source/blender/draw/intern/draw_armature.c b/source/blender/draw/intern/draw_armature.c
index 58cf3aaf6cc..c7a88f7689e 100644
--- a/source/blender/draw/intern/draw_armature.c
+++ b/source/blender/draw/intern/draw_armature.c
@@ -98,7 +98,7 @@ static struct {
* \{ */
/* Octahedral */
-static void DRW_shgroup_bone_octahedral_solid(const float (*bone_mat)[4], const float color[4])
+static void drw_shgroup_bone_octahedral_solid(const float (*bone_mat)[4], const float color[4])
{
if (g_data.bone_octahedral_solid == NULL) {
struct Gwn_Batch *geom = DRW_cache_bone_octahedral_get();
@@ -108,7 +108,7 @@ static void DRW_shgroup_bone_octahedral_solid(const float (*bone_mat)[4], const
DRW_shgroup_call_dynamic_add(g_data.bone_octahedral_solid, bone_mat, color);
}
-static void DRW_shgroup_bone_octahedral_wire(const float (*bone_mat)[4], const float color[4])
+static void drw_shgroup_bone_octahedral_wire(const float (*bone_mat)[4], const float color[4])
{
if (g_data.bone_octahedral_wire == NULL) {
struct Gwn_Batch *geom = DRW_cache_bone_octahedral_wire_outline_get();
@@ -119,7 +119,7 @@ static void DRW_shgroup_bone_octahedral_wire(const float (*bone_mat)[4], const f
}
/* Box / B-Bone */
-static void DRW_shgroup_bone_box_solid(const float (*bone_mat)[4], const float color[4])
+static void drw_shgroup_bone_box_solid(const float (*bone_mat)[4], const float color[4])
{
if (g_data.bone_box_solid == NULL) {
struct Gwn_Batch *geom = DRW_cache_bone_box_get();
@@ -129,7 +129,7 @@ static void DRW_shgroup_bone_box_solid(const float (*bone_mat)[4], const float c
DRW_shgroup_call_dynamic_add(g_data.bone_box_solid, bone_mat, color);
}
-static void DRW_shgroup_bone_box_wire(const float (*bone_mat)[4], const float color[4])
+static void drw_shgroup_bone_box_wire(const float (*bone_mat)[4], const float color[4])
{
if (g_data.bone_box_wire == NULL) {
struct Gwn_Batch *geom = DRW_cache_bone_box_wire_outline_get();
@@ -140,7 +140,7 @@ static void DRW_shgroup_bone_box_wire(const float (*bone_mat)[4], const float co
}
/* Wire */
-static void DRW_shgroup_bone_wire_wire(const float (*bone_mat)[4], const float color[4])
+static void drw_shgroup_bone_wire_wire(const float (*bone_mat)[4], const float color[4])
{
if (g_data.bone_wire_wire == NULL) {
struct Gwn_Batch *geom = DRW_cache_bone_wire_wire_outline_get();
@@ -151,7 +151,7 @@ static void DRW_shgroup_bone_wire_wire(const float (*bone_mat)[4], const float c
}
/* Envelope */
-static void DRW_shgroup_bone_envelope_distance(
+static void drw_shgroup_bone_envelope_distance(
const float (*bone_mat)[4], const float color[4],
const float *radius_head, const float *radius_tail, const float *distance)
{
@@ -166,7 +166,7 @@ static void DRW_shgroup_bone_envelope_distance(
}
}
-static void DRW_shgroup_bone_envelope_solid(
+static void drw_shgroup_bone_envelope_solid(
const float (*bone_mat)[4], const float color[4],
const float *radius_head, const float *radius_tail)
{
@@ -178,7 +178,7 @@ static void DRW_shgroup_bone_envelope_solid(
DRW_shgroup_call_dynamic_add(g_data.bone_envelope_solid, bone_mat, color, radius_head, radius_tail);
}
-static void DRW_shgroup_bone_envelope_wire(
+static void drw_shgroup_bone_envelope_wire(
const float (*bone_mat)[4], const float color[4],
const float *radius_head, const float *radius_tail, const float *distance)
{
@@ -190,7 +190,7 @@ static void DRW_shgroup_bone_envelope_wire(
DRW_shgroup_call_dynamic_add(g_data.bone_envelope_wire, bone_mat, color, radius_head, radius_tail, distance);
}
-static void DRW_shgroup_bone_envelope_head_wire(
+static void drw_shgroup_bone_envelope_head_wire(
const float (*bone_mat)[4], const float color[4],
const float *radius_head, const float *radius_tail, const float *distance)
{
@@ -204,7 +204,7 @@ static void DRW_shgroup_bone_envelope_head_wire(
/* Custom (geometry) */
-static void DRW_shgroup_bone_custom_solid(const float (*bone_mat)[4], const float color[4], Object *custom)
+static void drw_shgroup_bone_custom_solid(const float (*bone_mat)[4], const float color[4], Object *custom)
{
/* grr, not re-using instances! */
struct Gwn_Batch *geom = DRW_cache_object_surface_get(custom);
@@ -214,7 +214,7 @@ static void DRW_shgroup_bone_custom_solid(const float (*bone_mat)[4], const floa
}
}
-static void DRW_shgroup_bone_custom_wire(const float (*bone_mat)[4], const float color[4], Object *custom)
+static void drw_shgroup_bone_custom_wire(const float (*bone_mat)[4], const float color[4], Object *custom)
{
/* grr, not re-using instances! */
struct Gwn_Batch *geom = DRW_cache_object_wire_outline_get(custom);
@@ -225,7 +225,7 @@ static void DRW_shgroup_bone_custom_wire(const float (*bone_mat)[4], const float
}
/* Head and tail sphere */
-static void DRW_shgroup_bone_point_solid(const float (*bone_mat)[4], const float color[4])
+static void drw_shgroup_bone_point_solid(const float (*bone_mat)[4], const float color[4])
{
if (g_data.bone_point_solid == NULL) {
struct Gwn_Batch *geom = DRW_cache_bone_point_get();
@@ -235,7 +235,7 @@ static void DRW_shgroup_bone_point_solid(const float (*bone_mat)[4], const float
DRW_shgroup_call_dynamic_add(g_data.bone_point_solid, bone_mat, color);
}
-static void DRW_shgroup_bone_point_wire(const float (*bone_mat)[4], const float color[4])
+static void drw_shgroup_bone_point_wire(const float (*bone_mat)[4], const float color[4])
{
if (g_data.bone_point_wire == NULL) {
struct Gwn_Batch *geom = DRW_cache_bone_point_wire_outline_get();
@@ -246,7 +246,7 @@ static void DRW_shgroup_bone_point_wire(const float (*bone_mat)[4], const float
}
/* Axes */
-static void DRW_shgroup_bone_axes(const float (*bone_mat)[4], const float color[4])
+static void drw_shgroup_bone_axes(const float (*bone_mat)[4], const float color[4])
{
if (g_data.bone_axes == NULL) {
struct Gwn_Batch *geom = DRW_cache_bone_arrows_get();
@@ -257,7 +257,7 @@ static void DRW_shgroup_bone_axes(const float (*bone_mat)[4], const float color[
}
/* Relationship lines */
-static void UNUSED_FUNCTION(DRW_shgroup_bone_relationship_lines)(const float head[3], const float tail[3])
+static void UNUSED_FUNCTION(drw_shgroup_bone_relationship_lines)(const float head[3], const float tail[3])
{
DRW_shgroup_call_dynamic_add(g_data.relationship_lines, head);
DRW_shgroup_call_dynamic_add(g_data.relationship_lines, tail);
@@ -918,7 +918,7 @@ static void draw_axes(EditBone *eBone, bPoseChannel *pchan)
const float *col = (g_theme.const_color) ? g_theme.const_color :
(BONE_FLAG(eBone, pchan) & BONE_SELECTED) ? g_theme.text_hi_color : g_theme.text_color;
- DRW_shgroup_bone_axes(BONE_VAR(eBone, pchan, disp_mat), col);
+ drw_shgroup_bone_axes(BONE_VAR(eBone, pchan, disp_mat), col);
}
static void draw_points(
@@ -971,14 +971,14 @@ static void draw_points(
if (eBone) {
if (!((eBone->parent) && !EBONE_VISIBLE(arm, eBone->parent))) {
if (is_envelope_draw) {
- DRW_shgroup_bone_envelope_solid(eBone->disp_mat, col_solid_root,
+ drw_shgroup_bone_envelope_solid(eBone->disp_mat, col_solid_root,
&eBone->rad_head, &envelope_ignore);
- DRW_shgroup_bone_envelope_head_wire(eBone->disp_mat, col_wire_root,
+ drw_shgroup_bone_envelope_head_wire(eBone->disp_mat, col_wire_root,
&eBone->rad_head, &envelope_ignore, &envelope_ignore);
}
else {
- DRW_shgroup_bone_point_solid(eBone->disp_mat, col_solid_root);
- DRW_shgroup_bone_point_wire(eBone->disp_mat, col_wire_root);
+ drw_shgroup_bone_point_solid(eBone->disp_mat, col_solid_root);
+ drw_shgroup_bone_point_wire(eBone->disp_mat, col_wire_root);
}
}
}
@@ -986,14 +986,14 @@ static void draw_points(
Bone *bone = pchan->bone;
if (!((bone->parent) && (bone->parent->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG)))) {
if (is_envelope_draw) {
- DRW_shgroup_bone_envelope_solid(pchan->disp_mat, col_solid_root,
+ drw_shgroup_bone_envelope_solid(pchan->disp_mat, col_solid_root,
&bone->rad_head, &envelope_ignore);
- DRW_shgroup_bone_envelope_head_wire(pchan->disp_mat, col_wire_root,
+ drw_shgroup_bone_envelope_head_wire(pchan->disp_mat, col_wire_root,
&bone->rad_head, &envelope_ignore, &envelope_ignore);
}
else {
- DRW_shgroup_bone_point_solid(pchan->disp_mat, col_solid_root);
- DRW_shgroup_bone_point_wire(pchan->disp_mat, col_wire_root);
+ drw_shgroup_bone_point_solid(pchan->disp_mat, col_solid_root);
+ drw_shgroup_bone_point_wire(pchan->disp_mat, col_wire_root);
}
}
}
@@ -1006,14 +1006,14 @@ static void draw_points(
if (is_envelope_draw) {
const float *rad_tail = eBone ? &eBone->rad_tail : &pchan->bone->rad_tail;
- DRW_shgroup_bone_envelope_solid(
+ drw_shgroup_bone_envelope_solid(
BONE_VAR(eBone, pchan, disp_mat), col_solid_tail, &envelope_ignore, rad_tail);
- DRW_shgroup_bone_envelope_head_wire(
+ drw_shgroup_bone_envelope_head_wire(
BONE_VAR(eBone, pchan, disp_mat), col_wire_tail, &envelope_ignore, rad_tail, &envelope_ignore);
}
else {
- DRW_shgroup_bone_point_solid(BONE_VAR(eBone, pchan, disp_tail_mat), col_solid_tail);
- DRW_shgroup_bone_point_wire(BONE_VAR(eBone, pchan, disp_tail_mat), col_wire_tail);
+ drw_shgroup_bone_point_solid(BONE_VAR(eBone, pchan, disp_tail_mat), col_solid_tail);
+ drw_shgroup_bone_point_wire(BONE_VAR(eBone, pchan, disp_tail_mat), col_wire_tail);
}
if (select_id != -1) {
@@ -1042,8 +1042,8 @@ static void draw_bone_custom_shape(
DRW_select_load_id(select_id | BONESEL_BONE);
}
- DRW_shgroup_bone_custom_solid(disp_mat, col_solid, pchan->custom);
- DRW_shgroup_bone_custom_wire(disp_mat, col_wire, pchan->custom);
+ drw_shgroup_bone_custom_solid(disp_mat, col_solid, pchan->custom);
+ drw_shgroup_bone_custom_wire(disp_mat, col_wire, pchan->custom);
if (select_id != -1) {
DRW_select_load_id(-1);
@@ -1075,15 +1075,15 @@ static void draw_bone_envelope(
if ((boneflag & BONE_NO_DEFORM) == 0 &&
((boneflag & BONE_SELECTED) || (eBone && (boneflag & (BONE_ROOTSEL | BONE_TIPSEL)))))
{
- DRW_shgroup_bone_envelope_distance(BONE_VAR(eBone, pchan, disp_mat), col_white, rad_head, rad_tail, distance);
+ drw_shgroup_bone_envelope_distance(BONE_VAR(eBone, pchan, disp_mat), col_white, rad_head, rad_tail, distance);
}
if (select_id != -1) {
DRW_select_load_id(select_id | BONESEL_BONE);
}
- DRW_shgroup_bone_envelope_solid(BONE_VAR(eBone, pchan, disp_mat), col_solid, rad_head, rad_tail);
- DRW_shgroup_bone_envelope_wire(BONE_VAR(eBone, pchan, disp_mat), col_wire, rad_head, rad_tail, distance);
+ drw_shgroup_bone_envelope_solid(BONE_VAR(eBone, pchan, disp_mat), col_solid, rad_head, rad_tail);
+ drw_shgroup_bone_envelope_wire(BONE_VAR(eBone, pchan, disp_mat), col_wire, rad_head, rad_tail, distance);
if (select_id != -1) {
DRW_select_load_id(-1);
@@ -1116,12 +1116,12 @@ static void draw_bone_wire(
BLI_assert(bbones_mat != NULL);
for (int i = pchan->bone->segments; i--; bbones_mat++) {
- DRW_shgroup_bone_wire_wire(bbones_mat->mat, col_wire);
+ drw_shgroup_bone_wire_wire(bbones_mat->mat, col_wire);
}
}
else if (eBone) {
for (int i = 0; i < eBone->segments; i++) {
- DRW_shgroup_bone_wire_wire(eBone->disp_bbone_mat[i], col_wire);
+ drw_shgroup_bone_wire_wire(eBone->disp_bbone_mat[i], col_wire);
}
}
@@ -1151,14 +1151,14 @@ static void draw_bone_box(
BLI_assert(bbones_mat != NULL);
for (int i = pchan->bone->segments; i--; bbones_mat++) {
- DRW_shgroup_bone_box_solid(bbones_mat->mat, col_solid);
- DRW_shgroup_bone_box_wire(bbones_mat->mat, col_wire);
+ drw_shgroup_bone_box_solid(bbones_mat->mat, col_solid);
+ drw_shgroup_bone_box_wire(bbones_mat->mat, col_wire);
}
}
else if (eBone) {
for (int i = 0; i < eBone->segments; i++) {
- DRW_shgroup_bone_box_solid(eBone->disp_bbone_mat[i], col_solid);
- DRW_shgroup_bone_box_wire(eBone->disp_bbone_mat[i], col_wire);
+ drw_shgroup_bone_box_solid(eBone->disp_bbone_mat[i], col_solid);
+ drw_shgroup_bone_box_wire(eBone->disp_bbone_mat[i], col_wire);
}
}
@@ -1183,8 +1183,8 @@ static void draw_bone_octahedral(
DRW_select_load_id(select_id | BONESEL_BONE);
}
- DRW_shgroup_bone_octahedral_solid(BONE_VAR(eBone, pchan, disp_mat), col_solid);
- DRW_shgroup_bone_octahedral_wire(BONE_VAR(eBone, pchan, disp_mat), col_wire);
+ drw_shgroup_bone_octahedral_solid(BONE_VAR(eBone, pchan, disp_mat), col_solid);
+ drw_shgroup_bone_octahedral_wire(BONE_VAR(eBone, pchan, disp_mat), col_wire);
if (select_id != -1) {
DRW_select_load_id(-1);
@@ -1397,7 +1397,7 @@ static void draw_armature_pose(Object *ob, const float const_color[4])
/**
* This function set the object space to use for all subsequent `DRW_shgroup_bone_*` calls.
*/
-static void DRW_shgroup_armature(
+static void drw_shgroup_armature(
Object *ob, DRWPass *pass_bone_solid, DRWPass *pass_bone_wire, DRWPass *pass_bone_envelope,
DRWShadingGroup *shgrp_relationship_lines)
{
@@ -1419,7 +1419,7 @@ void DRW_shgroup_armature_object(
float *color;
DRW_object_wire_theme_get(ob, view_layer, &color);
- DRW_shgroup_armature(ob, pass_bone_solid, pass_bone_wire, NULL, shgrp_relationship_lines);
+ drw_shgroup_armature(ob, pass_bone_solid, pass_bone_wire, NULL, shgrp_relationship_lines);
draw_armature_pose(ob, color);
}
@@ -1427,7 +1427,7 @@ void DRW_shgroup_armature_pose(
Object *ob, DRWPass *pass_bone_solid, DRWPass *pass_bone_wire, DRWPass *pass_bone_envelope,
DRWShadingGroup *shgrp_relationship_lines)
{
- DRW_shgroup_armature(ob, pass_bone_solid, pass_bone_wire, pass_bone_envelope, shgrp_relationship_lines);
+ drw_shgroup_armature(ob, pass_bone_solid, pass_bone_wire, pass_bone_envelope, shgrp_relationship_lines);
draw_armature_pose(ob, NULL);
}
@@ -1435,7 +1435,7 @@ void DRW_shgroup_armature_edit(
Object *ob, DRWPass *pass_bone_solid, DRWPass *pass_bone_wire, DRWPass *pass_bone_envelope,
DRWShadingGroup *shgrp_relationship_lines)
{
- DRW_shgroup_armature(ob, pass_bone_solid, pass_bone_wire, pass_bone_envelope, shgrp_relationship_lines);
+ drw_shgroup_armature(ob, pass_bone_solid, pass_bone_wire, pass_bone_envelope, shgrp_relationship_lines);
draw_armature_edit(ob);
}
diff --git a/source/blender/draw/intern/draw_cache_impl_metaball.c b/source/blender/draw/intern/draw_cache_impl_metaball.c
index e8ad3e62139..e2dba8e626e 100644
--- a/source/blender/draw/intern/draw_cache_impl_metaball.c
+++ b/source/blender/draw/intern/draw_cache_impl_metaball.c
@@ -45,44 +45,6 @@
static void metaball_batch_cache_clear(MetaBall *mb);
/* ---------------------------------------------------------------------- */
-/* MetaBall Interface, indirect, partially cached access to complex data. */
-
-typedef struct MetaBallRenderData {
- int types;
-
- /* borrow from 'Object' */
- CurveCache *ob_curve_cache;
-} MetaBallRenderData;
-
-enum {
- /* Geometry */
- MBALL_DATATYPE_SURFACE = 1 << 0,
-// MBALL_DATATYPE_WIRE = 1 << 1,
-// MBALL_DATATYPE_SHADING = 1 << 2,
-};
-
-static MetaBallRenderData *metaball_render_data_create(
- MetaBall *UNUSED(mb), CurveCache *ob_curve_cache, const int types)
-{
- MetaBallRenderData *rdata = MEM_callocN(sizeof(*rdata), __func__);
- rdata->types = types;
- rdata->ob_curve_cache = ob_curve_cache;
-
-/*
- **TODO**
- if (types & MBALL_DATATYPE_WIRE) {}
- if (types & MBALL_DATATYPE_SHADING) {}
-*/
-
- return rdata;
-}
-
-static void metaball_render_data_free(MetaBallRenderData *rdata)
-{
- MEM_freeN(rdata);
-}
-
-/* ---------------------------------------------------------------------- */
/* MetaBall Gwn_Batch Cache */
typedef struct MetaBallBatchCache {
@@ -158,24 +120,6 @@ void DRW_mball_batch_cache_free(MetaBall *mb)
/* -------------------------------------------------------------------- */
-/** \name Private MetaBall Cache API
- * \{ */
-
-/* Gwn_Batch cache usage. */
-
-static Gwn_Batch *metaball_batch_cache_get_pos_and_normals(MetaBallRenderData *rdata, MetaBallBatchCache *cache)
-{
- BLI_assert(rdata->types & MBALL_DATATYPE_SURFACE);
- if (cache->batch == NULL) {
- cache->batch = BLI_displist_batch_calc_surface(&rdata->ob_curve_cache->disp);
- }
- return cache->batch;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-
/** \name Public Object/MetaBall API
* \{ */
@@ -188,9 +132,7 @@ Gwn_Batch *DRW_metaball_batch_cache_get_triangles_with_normals(Object *ob)
MetaBallBatchCache *cache = metaball_batch_cache_get(mb);
if (cache->batch == NULL) {
- MetaBallRenderData *rdata = metaball_render_data_create(mb, ob->curve_cache, MBALL_DATATYPE_SURFACE);
- metaball_batch_cache_get_pos_and_normals(rdata, cache);
- metaball_render_data_free(rdata);
+ cache->batch = BLI_displist_batch_calc_surface(&ob->curve_cache->disp);
}
return cache->batch;
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 1e0061bc29c..264fc079e42 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -101,29 +101,29 @@
#define USE_PROFILE
#ifdef USE_PROFILE
-#include "PIL_time.h"
+# include "PIL_time.h"
-#define PROFILE_TIMER_FALLOFF 0.1
+# define PROFILE_TIMER_FALLOFF 0.1
-#define PROFILE_START(time_start) \
+# define PROFILE_START(time_start) \
double time_start = PIL_check_seconds_timer();
-#define PROFILE_END_ACCUM(time_accum, time_start) { \
+# define PROFILE_END_ACCUM(time_accum, time_start) { \
time_accum += (PIL_check_seconds_timer() - time_start) * 1e3; \
} ((void)0)
/* exp average */
-#define PROFILE_END_UPDATE(time_update, time_start) { \
+# define PROFILE_END_UPDATE(time_update, time_start) { \
double _time_delta = (PIL_check_seconds_timer() - time_start) * 1e3; \
time_update = (time_update * (1.0 - PROFILE_TIMER_FALLOFF)) + \
(_time_delta * PROFILE_TIMER_FALLOFF); \
} ((void)0)
-#else
+#else /* USE_PROFILE */
-#define PROFILE_START(time_start) ((void)0)
-#define PROFILE_END_ACCUM(time_accum, time_start) ((void)0)
-#define PROFILE_END_UPDATE(time_update, time_start) ((void)0)
+# define PROFILE_START(time_start) ((void)0)
+# define PROFILE_END_ACCUM(time_accum, time_start) ((void)0)
+# define PROFILE_END_UPDATE(time_update, time_start) ((void)0)
#endif /* USE_PROFILE */
@@ -150,7 +150,7 @@ extern char datatoc_gpu_shader_3D_vert_glsl[];
extern char datatoc_gpu_shader_fullscreen_vert_glsl[];
/* Prototypes. */
-static void DRW_engines_enable_external(void);
+static void drw_engines_enable_external(void);
/* Structures */
typedef enum {
@@ -658,7 +658,7 @@ void DRW_shader_free(GPUShader *shader)
/** \name Interface (DRW_interface)
* \{ */
-static void DRW_interface_create(DRWInterface *interface, GPUShader *shader)
+static void drw_interface_create(DRWInterface *interface, GPUShader *shader)
{
interface->model = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_MODEL);
interface->modelinverse = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_MODEL_INV);
@@ -691,7 +691,7 @@ static void DRW_interface_create(DRWInterface *interface, GPUShader *shader)
}
-static void DRW_interface_uniform(DRWShadingGroup *shgroup, const char *name,
+static void drw_interface_uniform(DRWShadingGroup *shgroup, const char *name,
DRWUniformType type, const void *value, int length, int arraysize)
{
int location;
@@ -725,7 +725,7 @@ static void DRW_interface_uniform(DRWShadingGroup *shgroup, const char *name,
shgroup->interface.uniforms = uni;
}
-static void DRW_interface_attrib(DRWShadingGroup *shgroup, const char *name, DRWAttribType type, int size, bool dummy)
+static void drw_interface_attrib(DRWShadingGroup *shgroup, const char *name, DRWAttribType type, int size, bool dummy)
{
DRWAttrib *attrib = BLI_mempool_alloc(DST.vmempool->attribs);
GLuint program = GPU_shader_get_program(shgroup->shader);
@@ -788,7 +788,7 @@ DRWShadingGroup *DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass)
pass->shgroups_last = shgroup;
shgroup->next = NULL;
- DRW_interface_create(&shgroup->interface, shader);
+ drw_interface_create(&shgroup->interface, shader);
shgroup->type = DRW_SHG_NORMAL;
shgroup->shader = shader;
@@ -900,7 +900,7 @@ DRWShadingGroup *DRW_shgroup_material_empty_tri_batch_create(
if (shgroup) {
shgroup->type = DRW_SHG_TRIANGLE_BATCH;
shgroup->interface.instance_count = size * 3;
- DRW_interface_attrib(shgroup, "dummy", DRW_ATTRIB_FLOAT, 1, true);
+ drw_interface_attrib(shgroup, "dummy", DRW_ATTRIB_FLOAT, 1, true);
}
return shgroup;
@@ -945,7 +945,7 @@ DRWShadingGroup *DRW_shgroup_empty_tri_batch_create(struct GPUShader *shader, DR
shgroup->type = DRW_SHG_TRIANGLE_BATCH;
shgroup->interface.instance_count = size * 3;
- DRW_interface_attrib(shgroup, "dummy", DRW_ATTRIB_FLOAT, 1, true);
+ drw_interface_attrib(shgroup, "dummy", DRW_ATTRIB_FLOAT, 1, true);
return shgroup;
}
@@ -1143,82 +1143,82 @@ void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, unsigned int mask)
void DRW_shgroup_attrib_float(DRWShadingGroup *shgroup, const char *name, int size)
{
- DRW_interface_attrib(shgroup, name, DRW_ATTRIB_FLOAT, size, false);
+ drw_interface_attrib(shgroup, name, DRW_ATTRIB_FLOAT, size, false);
}
void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const GPUTexture *tex)
{
- DRW_interface_uniform(shgroup, name, DRW_UNIFORM_TEXTURE, tex, 0, 1);
+ drw_interface_uniform(shgroup, name, DRW_UNIFORM_TEXTURE, tex, 0, 1);
}
void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, const char *name, const GPUUniformBuffer *ubo)
{
- DRW_interface_uniform(shgroup, name, DRW_UNIFORM_BLOCK, ubo, 0, 1);
+ drw_interface_uniform(shgroup, name, DRW_UNIFORM_BLOCK, ubo, 0, 1);
}
void DRW_shgroup_uniform_buffer(DRWShadingGroup *shgroup, const char *name, GPUTexture **tex)
{
- DRW_interface_uniform(shgroup, name, DRW_UNIFORM_BUFFER, tex, 0, 1);
+ drw_interface_uniform(shgroup, name, DRW_UNIFORM_BUFFER, tex, 0, 1);
}
void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup, const char *name, const bool *value, int arraysize)
{
- DRW_interface_uniform(shgroup, name, DRW_UNIFORM_BOOL, value, 1, arraysize);
+ drw_interface_uniform(shgroup, name, DRW_UNIFORM_BOOL, value, 1, arraysize);
}
void DRW_shgroup_uniform_float(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize)
{
- DRW_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 1, arraysize);
+ drw_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 1, arraysize);
}
void DRW_shgroup_uniform_vec2(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize)
{
- DRW_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 2, arraysize);
+ drw_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 2, arraysize);
}
void DRW_shgroup_uniform_vec3(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize)
{
- DRW_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 3, arraysize);
+ drw_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 3, arraysize);
}
void DRW_shgroup_uniform_vec4(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize)
{
- DRW_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 4, arraysize);
+ drw_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 4, arraysize);
}
void DRW_shgroup_uniform_short_to_int(DRWShadingGroup *shgroup, const char *name, const short *value, int arraysize)
{
- DRW_interface_uniform(shgroup, name, DRW_UNIFORM_SHORT_TO_INT, value, 1, arraysize);
+ drw_interface_uniform(shgroup, name, DRW_UNIFORM_SHORT_TO_INT, value, 1, arraysize);
}
void DRW_shgroup_uniform_short_to_float(DRWShadingGroup *shgroup, const char *name, const short *value, int arraysize)
{
- DRW_interface_uniform(shgroup, name, DRW_UNIFORM_SHORT_TO_FLOAT, value, 1, arraysize);
+ drw_interface_uniform(shgroup, name, DRW_UNIFORM_SHORT_TO_FLOAT, value, 1, arraysize);
}
void DRW_shgroup_uniform_int(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize)
{
- DRW_interface_uniform(shgroup, name, DRW_UNIFORM_INT, value, 1, arraysize);
+ drw_interface_uniform(shgroup, name, DRW_UNIFORM_INT, value, 1, arraysize);
}
void DRW_shgroup_uniform_ivec2(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize)
{
- DRW_interface_uniform(shgroup, name, DRW_UNIFORM_INT, value, 2, arraysize);
+ drw_interface_uniform(shgroup, name, DRW_UNIFORM_INT, value, 2, arraysize);
}
void DRW_shgroup_uniform_ivec3(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize)
{
- DRW_interface_uniform(shgroup, name, DRW_UNIFORM_INT, value, 3, arraysize);
+ drw_interface_uniform(shgroup, name, DRW_UNIFORM_INT, value, 3, arraysize);
}
void DRW_shgroup_uniform_mat3(DRWShadingGroup *shgroup, const char *name, const float *value)
{
- DRW_interface_uniform(shgroup, name, DRW_UNIFORM_MAT3, value, 9, 1);
+ drw_interface_uniform(shgroup, name, DRW_UNIFORM_MAT3, value, 9, 1);
}
void DRW_shgroup_uniform_mat4(DRWShadingGroup *shgroup, const char *name, const float *value)
{
- DRW_interface_uniform(shgroup, name, DRW_UNIFORM_MAT4, value, 16, 1);
+ drw_interface_uniform(shgroup, name, DRW_UNIFORM_MAT4, value, 16, 1);
}
/* Creates a VBO containing OGL primitives for all DRWCallDynamic */
@@ -1449,7 +1449,7 @@ void DRW_pass_sort_shgroup_z(DRWPass *pass)
DRWShadingGroup *last = pass->shgroups;
while ((last = last->next)) {
/* Do nothing */
- };
+ }
pass->shgroups_last = last;
}
}
@@ -1462,7 +1462,7 @@ void DRW_pass_sort_shgroup_z(DRWPass *pass)
/** \name Draw (DRW_draw)
* \{ */
-static void DRW_state_set(DRWState state)
+static void drw_state_set(DRWState state)
{
if (DST.state == state) {
return;
@@ -1711,7 +1711,7 @@ static void DRW_state_set(DRWState state)
DST.state = state;
}
-static void DRW_stencil_set(unsigned int mask)
+static void drw_stencil_set(unsigned int mask)
{
if (DST.stencil_mask != mask) {
/* Stencil Write */
@@ -1954,8 +1954,8 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
release_texture_slots();
release_ubo_slots();
- DRW_state_set((pass_state & shgroup->state_extra_disable) | shgroup->state_extra);
- DRW_stencil_set(shgroup->stencil_mask);
+ drw_state_set((pass_state & shgroup->state_extra_disable) | shgroup->state_extra);
+ drw_stencil_set(shgroup->stencil_mask);
/* Binding Uniform */
/* Don't check anything, Interface should already contain the least uniform as possible */
@@ -2044,8 +2044,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
}
}
else {
- for (DRWCall *call = shgroup->calls_first; call; call = call->head.prev)
- {
+ for (DRWCall *call = shgroup->calls_first; call; call = call->head.prev) {
bool neg_scale = is_negative_m4(call->obmat);
/* Negative scale objects */
@@ -2076,12 +2075,12 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
DRW_state_reset();
}
-static void DRW_draw_pass_ex(DRWPass *pass, DRWShadingGroup *start_group, DRWShadingGroup *end_group)
+static void drw_draw_pass_ex(DRWPass *pass, DRWShadingGroup *start_group, DRWShadingGroup *end_group)
{
/* Start fresh */
DST.shader = NULL;
- DRW_state_set(pass->state);
+ drw_state_set(pass->state);
DRW_stats_query_start(pass->name);
@@ -2111,13 +2110,13 @@ static void DRW_draw_pass_ex(DRWPass *pass, DRWShadingGroup *start_group, DRWSha
void DRW_draw_pass(DRWPass *pass)
{
- DRW_draw_pass_ex(pass, pass->shgroups, pass->shgroups_last);
+ drw_draw_pass_ex(pass, pass->shgroups, pass->shgroups_last);
}
/* Draw only a subset of shgroups. Used in special situations as grease pencil strokes */
void DRW_draw_pass_subset(DRWPass *pass, DRWShadingGroup *start_group, DRWShadingGroup *end_group)
{
- DRW_draw_pass_ex(pass, start_group, end_group);
+ drw_draw_pass_ex(pass, start_group, end_group);
}
void DRW_draw_callbacks_pre_scene(void)
@@ -2140,7 +2139,7 @@ void DRW_draw_callbacks_post_scene(void)
void DRW_state_reset_ex(DRWState state)
{
DST.state = ~state;
- DRW_state_set(state);
+ drw_state_set(state);
}
void DRW_state_reset(void)
@@ -2428,7 +2427,7 @@ void DRW_framebuffer_viewport_size(struct GPUFrameBuffer *UNUSED(fb_read), int x
/* Use color management profile to draw texture to framebuffer */
void DRW_transform_to_display(GPUTexture *tex)
{
- DRW_state_set(DRW_STATE_WRITE_COLOR);
+ drw_state_set(DRW_STATE_WRITE_COLOR);
Gwn_VertFormat *vert_format = immVertexFormat();
unsigned int pos = GWN_vertformat_attr_add(vert_format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
@@ -2489,7 +2488,7 @@ void DRW_transform_to_display(GPUTexture *tex)
/** \name Viewport (DRW_viewport)
* \{ */
-static void *DRW_viewport_engine_data_get(void *engine_type)
+static void *DRW_viewport_engine_data_ensure(void *engine_type)
{
void *data = GPU_viewport_engine_data_get(DST.viewport, engine_type);
@@ -2534,7 +2533,7 @@ const float *DRW_viewport_pixelsize_get(void)
return &DST.pixsize;
}
-static void DRW_viewport_cache_resize(void)
+static void drw_viewport_cache_resize(void)
{
/* Release the memiter before clearing the mempools that references them */
GPU_viewport_cache_release(DST.viewport);
@@ -2554,7 +2553,7 @@ static void DRW_viewport_cache_resize(void)
* This is because a cache uniform only store reference
* to its value. And we don't want to invalidate the cache
* if this value change per viewport */
-static void DRW_viewport_var_init(void)
+static void drw_viewport_var_init(void)
{
RegionView3D *rv3d = DST.draw_ctx.rv3d;
@@ -2702,7 +2701,17 @@ void DRW_viewport_request_redraw(void)
/** \name ViewLayers (DRW_scenelayer)
* \{ */
-void **DRW_view_layer_engine_data_get(DrawEngineType *engine_type, void (*callback)(void *storage))
+void *DRW_view_layer_engine_data_get(DrawEngineType *engine_type)
+{
+ for (ViewLayerEngineData *sled = DST.draw_ctx.view_layer->drawdata.first; sled; sled = sled->next) {
+ if (sled->engine_type == engine_type) {
+ return sled->storage;
+ }
+ }
+ return NULL;
+}
+
+void **DRW_view_layer_engine_data_ensure(DrawEngineType *engine_type, void (*callback)(void *storage))
{
ViewLayerEngineData *sled;
@@ -2728,7 +2737,17 @@ void **DRW_view_layer_engine_data_get(DrawEngineType *engine_type, void (*callba
/** \name Objects (DRW_object)
* \{ */
-void **DRW_object_engine_data_get(
+void *DRW_object_engine_data_get(Object *ob, DrawEngineType *engine_type)
+{
+ for (ObjectEngineData *oed = ob->drawdata.first; oed; oed = oed->next) {
+ if (oed->engine_type == engine_type) {
+ return oed->storage;
+ }
+ }
+ return NULL;
+}
+
+void **DRW_object_engine_data_ensure(
Object *ob, DrawEngineType *engine_type, void (*callback)(void *storage))
{
ObjectEngineData *oed;
@@ -2747,9 +2766,9 @@ void **DRW_object_engine_data_get(
return &oed->storage;
}
-/* XXX There is definitly some overlap between this and DRW_object_engine_data_get.
+/* XXX There is definitly some overlap between this and DRW_object_engine_data_ensure.
* We should get rid of one of the two. */
-LampEngineData *DRW_lamp_engine_data_get(Object *ob, RenderEngineType *engine_type)
+LampEngineData *DRW_lamp_engine_data_ensure(Object *ob, RenderEngineType *engine_type)
{
BLI_assert(ob->type == OB_LAMP);
@@ -2773,11 +2792,11 @@ void DRW_lamp_engine_data_free(LampEngineData *led)
/** \name Rendering (DRW_engines)
* \{ */
-static void DRW_engines_init(void)
+static void drw_engines_init(void)
{
for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
DrawEngineType *engine = link->data;
- ViewportEngineData *data = DRW_viewport_engine_data_get(engine);
+ ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine);
PROFILE_START(stime);
if (engine->engine_init) {
@@ -2788,11 +2807,11 @@ static void DRW_engines_init(void)
}
}
-static void DRW_engines_cache_init(void)
+static void drw_engines_cache_init(void)
{
for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
DrawEngineType *engine = link->data;
- ViewportEngineData *data = DRW_viewport_engine_data_get(engine);
+ ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine);
if (data->text_draw_cache) {
DRW_text_cache_destroy(data->text_draw_cache);
@@ -2808,11 +2827,11 @@ static void DRW_engines_cache_init(void)
}
}
-static void DRW_engines_cache_populate(Object *ob)
+static void drw_engines_cache_populate(Object *ob)
{
for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
DrawEngineType *engine = link->data;
- ViewportEngineData *data = DRW_viewport_engine_data_get(engine);
+ ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine);
if (engine->cache_populate) {
engine->cache_populate(data, ob);
@@ -2820,11 +2839,11 @@ static void DRW_engines_cache_populate(Object *ob)
}
}
-static void DRW_engines_cache_finish(void)
+static void drw_engines_cache_finish(void)
{
for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
DrawEngineType *engine = link->data;
- ViewportEngineData *data = DRW_viewport_engine_data_get(engine);
+ ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine);
if (engine->cache_finish) {
engine->cache_finish(data);
@@ -2832,11 +2851,11 @@ static void DRW_engines_cache_finish(void)
}
}
-static void DRW_engines_draw_background(void)
+static void drw_engines_draw_background(void)
{
for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
DrawEngineType *engine = link->data;
- ViewportEngineData *data = DRW_viewport_engine_data_get(engine);
+ ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine);
if (engine->draw_background) {
PROFILE_START(stime);
@@ -2854,11 +2873,11 @@ static void DRW_engines_draw_background(void)
DRW_draw_background();
}
-static void DRW_engines_draw_scene(void)
+static void drw_engines_draw_scene(void)
{
for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
DrawEngineType *engine = link->data;
- ViewportEngineData *data = DRW_viewport_engine_data_get(engine);
+ ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine);
PROFILE_START(stime);
if (engine->draw_scene) {
@@ -2871,11 +2890,11 @@ static void DRW_engines_draw_scene(void)
}
}
-static void DRW_engines_draw_text(void)
+static void drw_engines_draw_text(void)
{
for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
DrawEngineType *engine = link->data;
- ViewportEngineData *data = DRW_viewport_engine_data_get(engine);
+ ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine);
PROFILE_START(stime);
if (data->text_draw_cache) {
@@ -2896,7 +2915,7 @@ int DRW_draw_region_engine_info_offset(void)
int lines = 0;
for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
DrawEngineType *engine = link->data;
- ViewportEngineData *data = DRW_viewport_engine_data_get(engine);
+ ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine);
/* Count the number of lines. */
if (data->info[0] != '\0') {
@@ -2931,7 +2950,7 @@ void DRW_draw_region_engine_info(void)
for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
DrawEngineType *engine = link->data;
- ViewportEngineData *data = DRW_viewport_engine_data_get(engine);
+ ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine);
if (data->info[0] != '\0') {
char *chr_current = data->info;
@@ -2978,24 +2997,24 @@ static void use_drw_engine(DrawEngineType *engine)
/* TODO revisit this when proper layering is implemented */
/* Gather all draw engines needed and store them in DST.enabled_engines
* That also define the rendering order of engines */
-static void DRW_engines_enable_from_engine(RenderEngineType *engine)
+static void drw_engines_enable_from_engine(RenderEngineType *engine_type)
{
/* TODO layers */
- if (engine->draw_engine != NULL) {
- use_drw_engine(engine->draw_engine);
+ if (engine_type->draw_engine != NULL) {
+ use_drw_engine(engine_type->draw_engine);
}
- if ((engine->flag & RE_INTERNAL) == 0) {
- DRW_engines_enable_external();
+ if ((engine_type->flag & RE_INTERNAL) == 0) {
+ drw_engines_enable_external();
}
}
-static void DRW_engines_enable_from_object_mode(void)
+static void drw_engines_enable_from_object_mode(void)
{
use_drw_engine(&draw_engine_object_type);
}
-static void DRW_engines_enable_from_mode(int mode)
+static void drw_engines_enable_from_mode(int mode)
{
switch (mode) {
case CTX_MODE_EDIT_MESH:
@@ -3049,7 +3068,7 @@ static void DRW_engines_enable_from_mode(int mode)
/**
* Use for select and depth-drawing.
*/
-static void DRW_engines_enable_basic(void)
+static void drw_engines_enable_basic(void)
{
use_drw_engine(DRW_engine_viewport_basic_type.draw_engine);
}
@@ -3057,25 +3076,25 @@ static void DRW_engines_enable_basic(void)
/**
* Use for external render engines.
*/
-static void DRW_engines_enable_external(void)
+static void drw_engines_enable_external(void)
{
use_drw_engine(DRW_engine_viewport_external_type.draw_engine);
}
-static void DRW_engines_enable(const Scene *scene, ViewLayer *view_layer, RenderEngineType *engine)
+static void drw_engines_enable(const Scene *scene, ViewLayer *view_layer, RenderEngineType *engine_type)
{
Object *obact = OBACT(view_layer);
const int mode = CTX_data_mode_enum_ex(scene->obedit, obact);
- DRW_engines_enable_from_engine(engine);
+ drw_engines_enable_from_engine(engine_type);
if (DRW_state_draw_support()) {
- DRW_engines_enable_from_object_mode();
- DRW_engines_enable_from_mode(mode);
+ drw_engines_enable_from_object_mode();
+ drw_engines_enable_from_mode(mode);
}
}
-static void DRW_engines_disable(void)
+static void drw_engines_disable(void)
{
BLI_freelistN(&DST.enabled_engines);
}
@@ -3101,7 +3120,7 @@ static void draw_stat(rcti *rect, int u, int v, const char *txt, const int size)
}
/* CPU stats */
-static void DRW_debug_cpu_stats(void)
+static void drw_debug_cpu_stats(void)
{
int u, v;
double init_tot_time = 0.0, background_tot_time = 0.0, render_tot_time = 0.0, tot_time = 0.0;
@@ -3133,7 +3152,7 @@ static void DRW_debug_cpu_stats(void)
for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
u = 0;
DrawEngineType *engine = link->data;
- ViewportEngineData *data = DRW_viewport_engine_data_get(engine);
+ ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine);
draw_stat(&rect, u++, v, engine->idname, sizeof(engine->idname));
@@ -3177,7 +3196,7 @@ static void DRW_debug_cpu_stats(void)
}
/* Display GPU time for each passes */
-static void DRW_debug_gpu_stats(void)
+static void drw_debug_gpu_stats(void)
{
/* local coordinate visible rect inside region, to accomodate overlapping ui */
rcti rect;
@@ -3219,15 +3238,14 @@ static void DRW_debug_gpu_stats(void)
/** \name View Update
* \{ */
-void DRW_notify_view_update(const bContext *C)
+void DRW_notify_view_update(const DRWUpdateContext *update_ctx)
{
- struct Depsgraph *graph = CTX_data_depsgraph(C);
- ARegion *ar = CTX_wm_region(C);
- View3D *v3d = CTX_wm_view3d(C);
+ RenderEngineType *engine_type = update_ctx->engine_type;
+ ARegion *ar = update_ctx->ar;
+ View3D *v3d = update_ctx->v3d;
RegionView3D *rv3d = ar->regiondata;
- Scene *scene = DEG_get_evaluated_scene(graph);
- RenderEngineType *engine = CTX_data_engine(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
+ Scene *scene = update_ctx->scene;
+ ViewLayer *view_layer = update_ctx->view_layer;
if (rv3d->viewport == NULL) {
return;
@@ -3239,14 +3257,14 @@ void DRW_notify_view_update(const bContext *C)
DST.viewport = rv3d->viewport;
DST.draw_ctx = (DRWContextState){
- ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine, C,
+ ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type, NULL,
};
- DRW_engines_enable(scene, view_layer, engine);
+ drw_engines_enable(scene, view_layer, engine_type);
for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
DrawEngineType *draw_engine = link->data;
- ViewportEngineData *data = DRW_viewport_engine_data_get(draw_engine);
+ ViewportEngineData *data = DRW_viewport_engine_data_ensure(draw_engine);
if (draw_engine->view_update) {
draw_engine->view_update(data);
@@ -3255,7 +3273,47 @@ void DRW_notify_view_update(const bContext *C)
DST.viewport = NULL;
- DRW_engines_disable();
+ drw_engines_disable();
+}
+
+/** \} */
+
+/** \name ID Update
+ * \{ */
+
+/* TODO(sergey): This code is run for each changed ID (including the ones which
+ * are changed indirectly via update flush. Need to find a way to make this to
+ * run really fast, hopefully without any memory allocations on a heap
+ * Idea here could be to run every known engine's id_update() and make them
+ * do nothing if there is no engine-specific data yet.
+ */
+void DRW_notify_id_update(const DRWUpdateContext *update_ctx, ID *id)
+{
+ RenderEngineType *engine_type = update_ctx->engine_type;
+ ARegion *ar = update_ctx->ar;
+ View3D *v3d = update_ctx->v3d;
+ RegionView3D *rv3d = ar->regiondata;
+ Scene *scene = update_ctx->scene;
+ ViewLayer *view_layer = update_ctx->view_layer;
+ if (rv3d->viewport == NULL) {
+ return;
+ }
+ /* Reset before using it. */
+ memset(&DST, 0x0, sizeof(DST));
+ DST.viewport = rv3d->viewport;
+ DST.draw_ctx = (DRWContextState){
+ ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type, NULL,
+ };
+ drw_engines_enable(scene, view_layer, engine_type);
+ for (LinkData *link = DST.enabled_engines.first; link; link = link->next) {
+ DrawEngineType *draw_engine = link->data;
+ ViewportEngineData *data = DRW_viewport_engine_data_ensure(draw_engine);
+ if (draw_engine->id_update) {
+ draw_engine->id_update(data, id);
+ }
+ }
+ DST.viewport = NULL;
+ drw_engines_disable();
}
/** \} */
@@ -3271,13 +3329,13 @@ void DRW_notify_view_update(const bContext *C)
void DRW_draw_view(const bContext *C)
{
struct Depsgraph *graph = CTX_data_depsgraph(C);
- RenderEngineType *engine = CTX_data_engine(C);
+ RenderEngineType *engine_type = CTX_data_engine_type(C);
ARegion *ar = CTX_wm_region(C);
View3D *v3d = CTX_wm_view3d(C);
/* Reset before using it. */
memset(&DST, 0x0, sizeof(DST));
- DRW_draw_render_loop_ex(graph, engine, ar, v3d, C);
+ DRW_draw_render_loop_ex(graph, engine_type, ar, v3d, C);
}
/**
@@ -3286,7 +3344,7 @@ void DRW_draw_view(const bContext *C)
*/
void DRW_draw_render_loop_ex(
struct Depsgraph *graph,
- RenderEngineType *engine,
+ RenderEngineType *engine_type,
ARegion *ar, View3D *v3d,
const bContext *evil_C)
{
@@ -3303,39 +3361,37 @@ void DRW_draw_render_loop_ex(
GPU_viewport_engines_data_validate(DST.viewport, DRW_engines_get_hash());
DST.draw_ctx = (DRWContextState){
- ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine,
+ ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type,
/* reuse if caller sets */
DST.draw_ctx.evil_C,
};
- DRW_viewport_var_init();
+ drw_viewport_var_init();
/* Get list of enabled engines */
- DRW_engines_enable(scene, view_layer, engine);
+ drw_engines_enable(scene, view_layer, engine_type);
/* Update ubos */
DRW_globals_update();
/* Init engines */
- DRW_engines_init();
+ drw_engines_init();
/* TODO : tag to refresh by the deps graph */
/* ideally only refresh when objects are added/removed */
/* or render properties / materials change */
{
PROFILE_START(stime);
- DRW_engines_cache_init();
+ drw_engines_cache_init();
- DEG_OBJECT_ITER(graph, ob, DEG_OBJECT_ITER_FLAG_ALL);
+ DEG_OBJECT_ITER(graph, ob, DEG_ITER_OBJECT_FLAG_ALL);
{
- DRW_engines_cache_populate(ob);
- /* XXX find a better place for this. maybe Depsgraph? */
- ob->deg_update_flag = 0;
+ drw_engines_cache_populate(ob);
}
DEG_OBJECT_ITER_END
- DRW_engines_cache_finish();
+ drw_engines_cache_finish();
PROFILE_END_ACCUM(DST.cache_time, stime);
}
@@ -3343,7 +3399,7 @@ void DRW_draw_render_loop_ex(
/* Start Drawing */
DRW_state_reset();
- DRW_engines_draw_background();
+ drw_engines_draw_background();
/* WIP, single image drawn over the camera view (replace) */
bool do_bg_image = false;
@@ -3358,7 +3414,7 @@ void DRW_draw_render_loop_ex(
}
extern void view3d_draw_bgpic_test(Scene *scene, ARegion *ar, View3D *v3d,
- const bool do_foreground, const bool do_camera_frame);
+ const bool do_foreground, const bool do_camera_frame);
if (do_bg_image) {
view3d_draw_bgpic_test(scene, ar, v3d, false, true);
}
@@ -3369,7 +3425,7 @@ void DRW_draw_render_loop_ex(
ED_region_draw_cb_draw(DST.draw_ctx.evil_C, DST.draw_ctx.ar, REGION_DRAW_PRE_VIEW);
}
- DRW_engines_draw_scene();
+ drw_engines_draw_scene();
DRW_draw_callbacks_post_scene();
if (DST.draw_ctx.evil_C) {
@@ -3378,7 +3434,7 @@ void DRW_draw_render_loop_ex(
DRW_state_reset();
- DRW_engines_draw_text();
+ drw_engines_draw_text();
if (DST.draw_ctx.evil_C) {
/* needed so manipulator isn't obscured */
@@ -3396,14 +3452,14 @@ void DRW_draw_render_loop_ex(
}
if (G.debug_value > 20) {
- DRW_debug_cpu_stats();
- DRW_debug_gpu_stats();
+ drw_debug_cpu_stats();
+ drw_debug_gpu_stats();
}
DRW_state_reset();
- DRW_engines_disable();
+ drw_engines_disable();
- DRW_viewport_cache_resize();
+ drw_viewport_cache_resize();
#ifdef DEBUG
/* Avoid accidental reuse. */
@@ -3419,13 +3475,13 @@ void DRW_draw_render_loop(
memset(&DST, 0x0, sizeof(DST));
Scene *scene = DEG_get_evaluated_scene(graph);
- RenderEngineType *engine = RE_engines_find(scene->view_render.engine_id);
+ RenderEngineType *engine_type = RE_engines_find(scene->view_render.engine_id);
- DRW_draw_render_loop_ex(graph, engine, ar, v3d, NULL);
+ DRW_draw_render_loop_ex(graph, engine_type, ar, v3d, NULL);
}
void DRW_draw_render_loop_offscreen(
- struct Depsgraph *graph, RenderEngineType *engine,
+ struct Depsgraph *graph, RenderEngineType *engine_type,
ARegion *ar, View3D *v3d, GPUOffScreen *ofs)
{
RegionView3D *rv3d = ar->regiondata;
@@ -3440,7 +3496,7 @@ void DRW_draw_render_loop_offscreen(
/* Reset before using it. */
memset(&DST, 0x0, sizeof(DST));
DST.options.is_image_render = true;
- DRW_draw_render_loop_ex(graph, engine, ar, v3d, NULL);
+ DRW_draw_render_loop_ex(graph, engine_type, ar, v3d, NULL);
/* restore */
{
@@ -3465,7 +3521,7 @@ void DRW_draw_select_loop(
bool UNUSED(use_obedit_skip), bool UNUSED(use_nearest), const rcti *rect)
{
Scene *scene = DEG_get_evaluated_scene(graph);
- RenderEngineType *engine = RE_engines_find(scene->view_render.engine_id);
+ RenderEngineType *engine_type = RE_engines_find(scene->view_render.engine_id);
ViewLayer *view_layer = DEG_get_evaluated_view_layer(graph);
#ifndef USE_GPU_SELECT
UNUSED_VARS(vc, scene, view_layer, v3d, ar, rect);
@@ -3505,11 +3561,11 @@ void DRW_draw_select_loop(
/* Get list of enabled engines */
if (use_obedit) {
- DRW_engines_enable_from_mode(obedit_mode);
+ drw_engines_enable_from_mode(obedit_mode);
}
else {
- DRW_engines_enable_basic();
- DRW_engines_enable_from_object_mode();
+ drw_engines_enable_basic();
+ drw_engines_enable_from_object_mode();
}
/* Setup viewport */
@@ -3517,49 +3573,48 @@ void DRW_draw_select_loop(
/* Instead of 'DRW_context_state_init(C, &DST.draw_ctx)', assign from args */
DST.draw_ctx = (DRWContextState){
- ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine, (bContext *)NULL,
+ ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type, (bContext *)NULL,
};
- DRW_viewport_var_init();
+ drw_viewport_var_init();
/* Update ubos */
DRW_globals_update();
/* Init engines */
- DRW_engines_init();
+ drw_engines_init();
/* TODO : tag to refresh by the deps graph */
/* ideally only refresh when objects are added/removed */
/* or render properties / materials change */
if (cache_is_dirty) {
-
- DRW_engines_cache_init();
+ drw_engines_cache_init();
if (use_obedit) {
- DRW_engines_cache_populate(scene->obedit);
+ drw_engines_cache_populate(scene->obedit);
}
else {
- DEG_OBJECT_ITER(graph, ob, DEG_OBJECT_ITER_FLAG_DUPLI)
+ DEG_OBJECT_ITER(graph, ob, DEG_ITER_OBJECT_FLAG_DUPLI)
{
if ((ob->base_flag & BASE_SELECTABLED) != 0) {
DRW_select_load_id(ob->select_color);
- DRW_engines_cache_populate(ob);
+ drw_engines_cache_populate(ob);
}
}
DEG_OBJECT_ITER_END
}
- DRW_engines_cache_finish();
+ drw_engines_cache_finish();
}
/* Start Drawing */
DRW_state_reset();
DRW_draw_callbacks_pre_scene();
- DRW_engines_draw_scene();
+ drw_engines_draw_scene();
DRW_draw_callbacks_post_scene();
DRW_state_reset();
- DRW_engines_disable();
+ drw_engines_disable();
#ifdef DEBUG
/* Avoid accidental reuse. */
@@ -3583,7 +3638,7 @@ void DRW_draw_depth_loop(
ARegion *ar, View3D *v3d)
{
Scene *scene = DEG_get_evaluated_scene(graph);
- RenderEngineType *engine = RE_engines_find(scene->view_render.engine_id);
+ RenderEngineType *engine_type = RE_engines_find(scene->view_render.engine_id);
ViewLayer *view_layer = DEG_get_evaluated_view_layer(graph);
RegionView3D *rv3d = ar->regiondata;
@@ -3605,8 +3660,8 @@ void DRW_draw_depth_loop(
/* Get list of enabled engines */
{
- DRW_engines_enable_basic();
- DRW_engines_enable_from_object_mode();
+ drw_engines_enable_basic();
+ drw_engines_enable_from_object_mode();
}
/* Setup viewport */
@@ -3614,41 +3669,40 @@ void DRW_draw_depth_loop(
/* Instead of 'DRW_context_state_init(C, &DST.draw_ctx)', assign from args */
DST.draw_ctx = (DRWContextState){
- ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine, (bContext *)NULL,
+ ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type, (bContext *)NULL,
};
- DRW_viewport_var_init();
+ drw_viewport_var_init();
/* Update ubos */
DRW_globals_update();
/* Init engines */
- DRW_engines_init();
+ drw_engines_init();
/* TODO : tag to refresh by the deps graph */
/* ideally only refresh when objects are added/removed */
/* or render properties / materials change */
if (cache_is_dirty) {
+ drw_engines_cache_init();
- DRW_engines_cache_init();
-
- DEG_OBJECT_ITER(graph, ob, DEG_OBJECT_ITER_FLAG_ALL)
+ DEG_OBJECT_ITER(graph, ob, DEG_ITER_OBJECT_FLAG_ALL)
{
- DRW_engines_cache_populate(ob);
+ drw_engines_cache_populate(ob);
}
DEG_OBJECT_ITER_END
- DRW_engines_cache_finish();
+ drw_engines_cache_finish();
}
/* Start Drawing */
DRW_state_reset();
DRW_draw_callbacks_pre_scene();
- DRW_engines_draw_scene();
+ drw_engines_draw_scene();
DRW_draw_callbacks_post_scene();
DRW_state_reset();
- DRW_engines_disable();
+ drw_engines_disable();
#ifdef DEBUG
/* Avoid accidental reuse. */
diff --git a/source/blender/draw/modes/edit_curve_mode.c b/source/blender/draw/modes/edit_curve_mode.c
index 1d542fc8e7e..1ecf1a60a35 100644
--- a/source/blender/draw/modes/edit_curve_mode.c
+++ b/source/blender/draw/modes/edit_curve_mode.c
@@ -89,7 +89,7 @@ typedef struct EDIT_CURVE_StorageList {
} EDIT_CURVE_StorageList;
typedef struct EDIT_CURVE_Data {
- /* Struct returned by DRW_viewport_engine_data_get.
+ /* Struct returned by DRW_viewport_engine_data_ensure.
* If you don't use one of these, just make it a (void *) */
// void *fbl;
void *engine_type; /* Required */
diff --git a/source/blender/draw/modes/edit_lattice_mode.c b/source/blender/draw/modes/edit_lattice_mode.c
index 675ea925a39..ff4c557326e 100644
--- a/source/blender/draw/modes/edit_lattice_mode.c
+++ b/source/blender/draw/modes/edit_lattice_mode.c
@@ -85,7 +85,7 @@ typedef struct EDIT_LATTICE_StorageList {
} EDIT_LATTICE_StorageList;
typedef struct EDIT_LATTICE_Data {
- /* Struct returned by DRW_viewport_engine_data_get.
+ /* Struct returned by DRW_viewport_engine_data_ensure.
* If you don't use one of these, just make it a (void *) */
// void *fbl;
void *engine_type; /* Required */
diff --git a/source/blender/draw/modes/edit_metaball_mode.c b/source/blender/draw/modes/edit_metaball_mode.c
index fb61114686b..a83f5ae33bc 100644
--- a/source/blender/draw/modes/edit_metaball_mode.c
+++ b/source/blender/draw/modes/edit_metaball_mode.c
@@ -81,7 +81,7 @@ typedef struct EDIT_METABALL_StorageList {
} EDIT_METABALL_StorageList;
typedef struct EDIT_METABALL_Data {
- /* Struct returned by DRW_viewport_engine_data_get.
+ /* Struct returned by DRW_viewport_engine_data_ensure.
* If you don't use one of these, just make it a (void *) */
// void *fbl;
void *engine_type; /* Required */
diff --git a/source/blender/draw/modes/edit_surface_mode.c b/source/blender/draw/modes/edit_surface_mode.c
index e99973144aa..4e60c4abff5 100644
--- a/source/blender/draw/modes/edit_surface_mode.c
+++ b/source/blender/draw/modes/edit_surface_mode.c
@@ -76,7 +76,7 @@ typedef struct EDIT_SURFACE_StorageList {
} EDIT_SURFACE_StorageList;
typedef struct EDIT_SURFACE_Data {
- /* Struct returned by DRW_viewport_engine_data_get.
+ /* Struct returned by DRW_viewport_engine_data_ensure.
* If you don't use one of these, just make it a (void *) */
// void *fbl;
void *engine_type; /* Required */
diff --git a/source/blender/draw/modes/edit_text_mode.c b/source/blender/draw/modes/edit_text_mode.c
index 476a2ab9ac2..b375bad84b5 100644
--- a/source/blender/draw/modes/edit_text_mode.c
+++ b/source/blender/draw/modes/edit_text_mode.c
@@ -83,7 +83,7 @@ typedef struct EDIT_TEXT_StorageList {
} EDIT_TEXT_StorageList;
typedef struct EDIT_TEXT_Data {
- /* Struct returned by DRW_viewport_engine_data_get.
+ /* Struct returned by DRW_viewport_engine_data_ensure.
* If you don't use one of these, just make it a (void *) */
// void *fbl;
void *engine_type; /* Required */
diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c
index a1bb12aec25..91b64818eff 100644
--- a/source/blender/draw/modes/object_mode.c
+++ b/source/blender/draw/modes/object_mode.c
@@ -1110,7 +1110,7 @@ static void DRW_shgroup_lamp(OBJECT_StorageList *stl, Object *ob, ViewLayer *vie
int theme_id = DRW_object_wire_theme_get(ob, view_layer, &color);
static float zero = 0.0f;
- float **la_mats = (float **)DRW_object_engine_data_get(ob, &draw_engine_object_type, NULL);
+ float **la_mats = (float **)DRW_object_engine_data_ensure(ob, &draw_engine_object_type, NULL);
if (*la_mats == NULL) {
/* we need 2 matrices */
*la_mats = MEM_mallocN(sizeof(float) * 16 * 2, "Lamp Object Mode Matrices");
@@ -1456,7 +1456,7 @@ static void DRW_shgroup_lightprobe(OBJECT_StorageList *stl, OBJECT_PassList *psl
DRW_object_wire_theme_get(ob, view_layer, &color);
OBJECT_LightProbeEngineData *prb_data;
- OBJECT_LightProbeEngineData **prb_data_pt = (OBJECT_LightProbeEngineData **)DRW_object_engine_data_get(ob, &draw_engine_object_type, NULL);
+ OBJECT_LightProbeEngineData **prb_data_pt = (OBJECT_LightProbeEngineData **)DRW_object_engine_data_ensure(ob, &draw_engine_object_type, NULL);
if (*prb_data_pt == NULL) {
*prb_data_pt = MEM_mallocN(sizeof(OBJECT_LightProbeEngineData), "Probe Clip distances Matrices");
}
diff --git a/source/blender/draw/modes/paint_texture_mode.c b/source/blender/draw/modes/paint_texture_mode.c
index f898770acef..b49da0cba2f 100644
--- a/source/blender/draw/modes/paint_texture_mode.c
+++ b/source/blender/draw/modes/paint_texture_mode.c
@@ -90,7 +90,7 @@ typedef struct PAINT_TEXTURE_StorageList {
} PAINT_TEXTURE_StorageList;
typedef struct PAINT_TEXTURE_Data {
- /* Struct returned by DRW_viewport_engine_data_get.
+ /* Struct returned by DRW_viewport_engine_data_ensure.
* If you don't use one of these, just make it a (void *) */
// void *fbl;
void *engine_type; /* Required */
diff --git a/source/blender/draw/modes/particle_mode.c b/source/blender/draw/modes/particle_mode.c
index be076815f4c..6a3e53a72c2 100644
--- a/source/blender/draw/modes/particle_mode.c
+++ b/source/blender/draw/modes/particle_mode.c
@@ -70,7 +70,7 @@ typedef struct PARTICLE_StorageList {
} PARTICLE_StorageList;
typedef struct PARTICLE_Data {
- /* Struct returned by DRW_viewport_engine_data_get.
+ /* Struct returned by DRW_viewport_engine_data_ensure.
* If you don't use one of these, just make it a (void *) */
// void *fbl;
void *engine_type; /* Required */
diff --git a/source/blender/draw/modes/sculpt_mode.c b/source/blender/draw/modes/sculpt_mode.c
index f38e6565065..d9f1f5ebe91 100644
--- a/source/blender/draw/modes/sculpt_mode.c
+++ b/source/blender/draw/modes/sculpt_mode.c
@@ -80,7 +80,7 @@ typedef struct SCULPT_StorageList {
} SCULPT_StorageList;
typedef struct SCULPT_Data {
- /* Struct returned by DRW_viewport_engine_data_get.
+ /* Struct returned by DRW_viewport_engine_data_ensure.
* If you don't use one of these, just make it a (void *) */
// void *fbl;
void *engine_type; /* Required */
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index e32324d25f9..b87942fed84 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -807,6 +807,7 @@ enum {
SIMEDBONE_PREFIX,
SIMEDBONE_SUFFIX,
SIMEDBONE_LAYER,
+ SIMEDBONE_GROUP,
SIMEDBONE_SHAPE,
};
@@ -819,6 +820,7 @@ static const EnumPropertyItem prop_similar_types[] = {
{SIMEDBONE_PREFIX, "PREFIX", 0, "Prefix", ""},
{SIMEDBONE_SUFFIX, "SUFFIX", 0, "Suffix", ""},
{SIMEDBONE_LAYER, "LAYER", 0, "Layer", ""},
+ {SIMEDBONE_GROUP, "GROUP", 0, "Group", ""},
{SIMEDBONE_SHAPE, "SHAPE", 0, "Shape", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -1009,6 +1011,9 @@ static int armature_select_similar_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+#define STRUCT_SIZE_AND_OFFSET(_struct, _member) \
+ sizeof(((_struct *)NULL)->_member), offsetof(_struct, _member)
+
switch (type) {
case SIMEDBONE_CHILDREN:
select_similar_children(arm, ebone_act);
@@ -1034,13 +1039,20 @@ static int armature_select_similar_exec(bContext *C, wmOperator *op)
case SIMEDBONE_LAYER:
select_similar_layer(arm, ebone_act);
break;
+ case SIMEDBONE_GROUP:
+ select_similar_data_pchan(
+ arm, obedit, ebone_act,
+ STRUCT_SIZE_AND_OFFSET(bPoseChannel, agrp_index));
+ break;
case SIMEDBONE_SHAPE:
select_similar_data_pchan(
arm, obedit, ebone_act,
- sizeof(void *), offsetof(bPoseChannel, custom));
+ STRUCT_SIZE_AND_OFFSET(bPoseChannel, custom));
break;
}
+#undef STRUCT_SIZE_AND_OFFSET
+
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c
index a240d6b190f..4dd8e4bd6fa 100644
--- a/source/blender/editors/armature/editarmature_sketch.c
+++ b/source/blender/editors/armature/editarmature_sketch.c
@@ -998,7 +998,7 @@ static int sk_getStrokeSnapPoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, S
* the ideal would be to call this function only at the beginning of the snap operation,
* or at the beginning of the operator itself */
struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d(
- CTX_data_main(C), CTX_data_scene(C), CTX_data_view_layer(C), CTX_data_engine(C), 0,
+ CTX_data_main(C), CTX_data_scene(C), CTX_data_view_layer(C), CTX_data_engine_type(C), 0,
CTX_wm_region(C), CTX_wm_view3d(C));
float mvalf[2] = {UNPACK2(dd->mval)};
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index e8c784f15d5..79b63f36b76 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -5020,7 +5020,7 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
const float mval[2] = {UNPACK2(event->mval)};
struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d(
- CTX_data_main(C), vc.scene, vc.view_layer, vc.engine, 0,
+ CTX_data_main(C), vc.scene, vc.view_layer, vc.engine_type, 0,
vc.ar, vc.v3d);
ED_transform_snap_object_project_view3d_mixed(
diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c
index 92daa802601..f3b12b9bc85 100644
--- a/source/blender/editors/gpencil/gpencil_convert.c
+++ b/source/blender/editors/gpencil/gpencil_convert.c
@@ -1156,7 +1156,7 @@ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bG
*/
ob = BKE_object_add_only_object(bmain, OB_CURVE, gpl->info);
cu = ob->data = BKE_curve_add(bmain, gpl->info, OB_CURVE);
- BKE_collection_object_add(scene, sc, ob);
+ BKE_collection_object_add(&scene->id, sc, ob);
base_new = BKE_view_layer_base_find(view_layer, ob);
cu->flag |= CU_3D;
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index 1c8cf0665b3..1fd7756df77 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -76,7 +76,6 @@ struct BMFace *EDBM_verts_mirror_get_face(struct BMEditMesh *em, struct BMFace *
void EDBM_verts_mirror_cache_clear(struct BMEditMesh *em, struct BMVert *v);
void EDBM_verts_mirror_cache_end(struct BMEditMesh *em);
-void EDBM_mesh_ensure_valid_dm_hack(struct Scene *scene, struct BMEditMesh *em);
void EDBM_mesh_normals_update(struct BMEditMesh *em);
void EDBM_mesh_clear(struct BMEditMesh *em);
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index 066c4e5a692..8d2ff327c51 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -82,7 +82,7 @@ typedef enum eParentType {
PAR_VERTEX_TRI,
} eParentType;
-typedef enum eObjectSelect_Mode{
+typedef enum eObjectSelect_Mode {
BA_DESELECT = 0,
BA_SELECT = 1,
BA_INVERT = 2,
diff --git a/source/blender/editors/include/ED_render.h b/source/blender/editors/include/ED_render.h
index 707d7c6c693..b7317d75cd4 100644
--- a/source/blender/editors/include/ED_render.h
+++ b/source/blender/editors/include/ED_render.h
@@ -31,6 +31,7 @@
#include "DNA_vec_types.h"
struct bContext;
+struct DEGEditorUpdateContext;
struct ID;
struct Main;
struct MTex;
@@ -43,13 +44,15 @@ struct wmWindowManager;
void ED_operatortypes_render(void);
-/* render_shading.c */
+/* render_update.c */
-void ED_render_id_flush_update(struct Main *bmain, struct ID *id);
void ED_render_engine_changed(struct Main *bmain);
void ED_render_engine_area_exit(struct Main *bmain, struct ScrArea *sa);
-void ED_render_scene_update(struct Main *bmain, struct Scene *scene, int updated);
-void ED_render_scene_update_pre(struct Main *bmain, struct Scene *scene, bool time);
+
+/* Callbacks handling data update events coming from depsgraph. */
+
+void ED_render_id_flush_update(const struct DEGEditorUpdateContext *update_ctx, struct ID *id);
+void ED_render_scene_update(const struct DEGEditorUpdateContext *update_ctx, int updated);
void ED_viewport_render_kill_jobs(struct wmWindowManager *wm, struct Main *bmain, bool free_database);
struct Scene *ED_render_job_get_scene(const struct bContext *C);
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index 6cb20c818fd..d931109b941 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -55,6 +55,9 @@ struct ARegion;
struct uiBlock;
struct rcti;
struct Main;
+struct wmMsgBus;
+struct wmMsgSubscribeKey;
+struct wmMsgSubscribeValue;
/* regions */
void ED_region_do_listen(
@@ -86,6 +89,18 @@ void ED_region_grid_draw(struct ARegion *ar, float zoomx, float zoomy);
float ED_region_blend_factor(struct ARegion *ar);
void ED_region_visible_rect(struct ARegion *ar, struct rcti *rect);
+/* message_bus callbacks */
+void ED_region_do_msg_notify_tag_redraw(
+ struct bContext *C, struct wmMsgSubscribeKey *msg_key, struct wmMsgSubscribeValue *msg_val);
+void ED_area_do_msg_notify_tag_refresh(
+ struct bContext *C, struct wmMsgSubscribeKey *msg_key, struct wmMsgSubscribeValue *msg_val);
+
+/* message bus */
+void ED_region_message_subscribe(
+ struct bContext *C,
+ struct WorkSpace *workspace, struct Scene *scene,
+ struct bScreen *screen, struct ScrArea *sa, struct ARegion *ar,
+ struct wmMsgBus *mbus);
/* spaces */
void ED_spacetypes_keymap(struct wmKeyConfig *keyconf);
@@ -153,6 +168,7 @@ void ED_screen_preview_render(const struct bScreen *screen, int size_x, int s
struct WorkSpace *ED_workspace_add(
struct Main *bmain,
const char *name,
+ Scene *scene,
ViewLayer *act_render_layer,
struct ViewRender *view_render) ATTR_NONNULL();
bool ED_workspace_change(
@@ -169,7 +185,8 @@ bool ED_workspace_delete(
void ED_workspace_scene_data_sync(
struct WorkSpaceInstanceHook *hook, Scene *scene) ATTR_NONNULL();
void ED_workspace_view_layer_unset(
- const struct Main *bmain, const ViewLayer *layer_unset, ViewLayer *layer_new) ATTR_NONNULL(1, 2);
+ const struct Main *bmain, struct Scene *scene,
+ const ViewLayer *layer_unset, ViewLayer *layer_new) ATTR_NONNULL(1, 2);
struct WorkSpaceLayout *ED_workspace_layout_add(
struct WorkSpace *workspace,
struct wmWindow *win,
diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h
index 49e85600819..8761f2c5361 100644
--- a/source/blender/editors/include/ED_transform_snap_object_context.h
+++ b/source/blender/editors/include/ED_transform_snap_object_context.h
@@ -76,9 +76,9 @@ struct SnapObjectParams {
typedef struct SnapObjectContext SnapObjectContext;
SnapObjectContext *ED_transform_snap_object_context_create(
- struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, struct RenderEngineType *engine, int flag);
+ struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, struct RenderEngineType *engine_type, int flag);
SnapObjectContext *ED_transform_snap_object_context_create_view3d(
- struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, struct RenderEngineType *engine, int flag,
+ struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, struct RenderEngineType *engine_type, int flag,
/* extra args for view3d */
const struct ARegion *ar, const struct View3D *v3d);
void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx);
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index feb3686db9f..69061bdcd26 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -78,7 +78,7 @@ typedef struct ViewContext {
struct Depsgraph *depsgraph;
struct Scene *scene;
struct ViewLayer *view_layer;
- struct RenderEngineType *engine;
+ struct RenderEngineType *engine_type;
struct Object *obact;
struct Object *obedit;
struct ARegion *ar;
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 51a98c47718..9a816f21fb8 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -73,6 +73,7 @@ struct bNodeSocket;
struct wmDropBox;
struct wmDrag;
struct wmEvent;
+struct wmMsgBus;
typedef struct uiBut uiBut;
typedef struct uiBlock uiBlock;
@@ -183,6 +184,8 @@ enum {
UI_BUT_UPDATE_DELAY = (1 << 28), /* don't run updates while dragging (needed in rare cases). */
UI_BUT_TEXTEDIT_UPDATE = (1 << 29), /* when widget is in textedit mode, update value on each char stroke */
UI_BUT_VALUE_CLEAR = (1 << 30), /* show 'x' icon to clear/unlink value of text or search button */
+
+ UI_BUT_OVERRIDEN = (1 << 31), /* RNA property of the button is overriden from linked reference data. */
};
#define UI_PANEL_WIDTH 340
@@ -901,6 +904,8 @@ uiLayout *UI_block_layout(uiBlock *block, int dir, int type, int x, int y, int s
void UI_block_layout_set_current(uiBlock *block, uiLayout *layout);
void UI_block_layout_resolve(uiBlock *block, int *x, int *y);
+void UI_region_message_subscribe(struct ARegion *ar, struct wmMsgBus *mbus);
+
uiBlock *uiLayoutGetBlock(uiLayout *layout);
void uiLayoutSetFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv);
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 09007681455..a5ef2943387 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -41,6 +41,7 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_userdef_types.h"
+#include "DNA_workspace_types.h"
#include "BLI_math.h"
#include "BLI_listbase.h"
@@ -69,11 +70,14 @@
#include "WM_api.h"
#include "WM_types.h"
#include "wm_subwindow.h"
+#include "WM_message.h"
#include "RNA_access.h"
#include "BPY_extern.h"
+#include "ED_screen.h"
+
#include "IMB_colormanagement.h"
#include "interface_intern.h"
@@ -1216,6 +1220,20 @@ static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block)
}
}
+void ui_but_override_flag(uiBut *but)
+{
+ bool is_overridden;
+
+ RNA_property_override_status(&but->rnapoin, but->rnaprop, but->rnaindex, NULL, &is_overridden, NULL, NULL);
+
+ if (is_overridden) {
+ but->flag |= UI_BUT_OVERRIDEN;
+ }
+ else {
+ but->flag &= ~UI_BUT_OVERRIDEN;
+ }
+}
+
void UI_block_update_from_old(const bContext *C, uiBlock *block)
{
uiBut *but_old;
@@ -1280,6 +1298,7 @@ void UI_block_end_ex(const bContext *C, uiBlock *block, const int xy[2], int r_x
}
ui_but_anim_flag(but, (scene) ? scene->r.cfra : 0.0f);
+ ui_but_override_flag(but);
}
@@ -1438,6 +1457,40 @@ void UI_block_draw(const bContext *C, uiBlock *block)
ui_draw_links(block);
}
+static void ui_block_message_subscribe(ARegion *ar, struct wmMsgBus *mbus, uiBlock *block)
+{
+ uiBut *but_prev = NULL;
+ /* possibly we should keep the region this block is contained in? */
+ for (uiBut *but = block->buttons.first; but; but = but->next) {
+ if (but->rnapoin.type && but->rnaprop) {
+ /* quick check to avoid adding buttons representing a vector, multiple times. */
+ if ((but_prev &&
+ (but_prev->rnaprop == but->rnaprop) &&
+ (but_prev->rnapoin.type == but->rnapoin.type) &&
+ (but_prev->rnapoin.data == but->rnapoin.data) &&
+ (but_prev->rnapoin.id.data == but->rnapoin.id.data)) == false)
+ {
+ /* TODO: could make this into utility function. */
+ WM_msg_subscribe_rna(
+ mbus, &but->rnapoin, but->rnaprop,
+ &(const wmMsgSubscribeValue){
+ .owner = ar,
+ .user_data = ar,
+ .notify = ED_region_do_msg_notify_tag_redraw,
+ }, __func__);
+ but_prev = but;
+ }
+ }
+ }
+}
+
+void UI_region_message_subscribe(ARegion *ar, struct wmMsgBus *mbus)
+{
+ for (uiBlock *block = ar->uiblocks.first; block; block = block->next) {
+ ui_block_message_subscribe(ar, mbus, block);
+ }
+}
+
/* ************* EVENTS ************* */
/**
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 908fa19e3b1..53505fc39a4 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -6800,6 +6800,8 @@ static bool ui_but_menu(bContext *C, uiBut *but)
MenuType *mt = WM_menutype_find("WM_MT_button_context", true);
bool is_array, is_array_component;
uiStringInfo label = {BUT_GET_LABEL, NULL};
+ wmOperatorType *ot;
+ PointerRNA op_ptr;
/* if ((but->rnapoin.data && but->rnaprop) == 0 && but->optype == NULL)*/
/* return 0;*/
@@ -6826,11 +6828,11 @@ static bool ui_but_menu(bContext *C, uiBut *but)
const PropertySubType subtype = RNA_property_subtype(prop);
bool is_anim = RNA_property_animateable(ptr, prop);
bool is_editable = RNA_property_editable(ptr, prop);
+ bool is_overridable;
/*bool is_idprop = RNA_property_is_idprop(prop);*/ /* XXX does not work as expected, not strictly needed */
bool is_set = RNA_property_is_set(ptr, prop);
- /* Set the (button_pointer, button_prop) and pointer data for Python access to the hovered ui element. */
- uiLayoutSetContextFromBut(layout, but);
+ RNA_property_override_status(ptr, prop, -1, &is_overridable, NULL, NULL, NULL);
/* second slower test, saved people finding keyframe items in menus when its not possible */
if (is_anim)
@@ -6959,11 +6961,57 @@ static bool ui_but_menu(bContext *C, uiBut *but)
ICON_NONE, "ANIM_OT_keyingset_button_remove");
}
}
-
+
+ if (is_overridable) {
+ /* Override Operators */
+ uiItemS(layout);
+
+ if (but->flag & UI_BUT_OVERRIDEN) {
+ if (is_array_component) {
+ ot = WM_operatortype_find("UI_OT_override_type_set_button", false);
+ uiItemFullO_ptr(layout, ot, "Overrides Type", ICON_NONE,
+ NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
+ RNA_boolean_set(&op_ptr, "all", true);
+ uiItemFullO_ptr(layout, ot, "Single Override Type", ICON_NONE,
+ NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
+ RNA_boolean_set(&op_ptr, "all", false);
+
+ uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Overrides"),
+ ICON_X, "UI_OT_override_remove_button", "all", true);
+ uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Single Override"),
+ ICON_X, "UI_OT_override_remove_button", "all", false);
+ }
+ else {
+ uiItemFullO(layout, "UI_OT_override_type_set_button", "Override Type", ICON_NONE,
+ NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
+ RNA_boolean_set(&op_ptr, "all", false);
+
+ uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Override"),
+ ICON_X, "UI_OT_override_remove_button", "all", true);
+ }
+ }
+ else {
+ if (is_array_component) {
+ ot = WM_operatortype_find("UI_OT_override_type_set_button", false);
+ uiItemFullO_ptr(layout, ot, "Define Overrides", ICON_NONE,
+ NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
+ RNA_boolean_set(&op_ptr, "all", true);
+ uiItemFullO_ptr(layout, ot, "Define Single Override", ICON_NONE,
+ NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
+ RNA_boolean_set(&op_ptr, "all", false);
+ }
+ else {
+ uiItemFullO(layout, "UI_OT_override_type_set_button", "Define Override", ICON_NONE,
+ NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
+ RNA_boolean_set(&op_ptr, "all", false);
+ }
+ }
+ }
+
uiItemS(layout);
-
+
/* Property Operators */
-
+
/* Copy Property Value
* Paste Property Value */
@@ -8241,6 +8289,7 @@ void UI_context_update_anim_flag(const bContext *C)
for (block = ar->uiblocks.first; block; block = block->next) {
for (but = block->buttons.first; but; but = but->next) {
ui_but_anim_flag(but, (scene) ? scene->r.cfra : 0.0f);
+ ui_but_override_flag(but);
ED_region_tag_redraw(ar);
if (but->active) {
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 424063953a7..6f450093d30 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -514,6 +514,7 @@ extern bool ui_but_supports_cycling(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
extern int ui_but_is_pushed_ex(uiBut *but, double *value) ATTR_WARN_UNUSED_RESULT;
extern int ui_but_is_pushed(uiBut *but) ATTR_WARN_UNUSED_RESULT;
+void ui_but_override_flag(uiBut *but);
extern void ui_block_bounds_calc(uiBlock *block);
extern void ui_block_translate(uiBlock *block, int x, int y);
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 5913f1c48f5..bbcd10270d5 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -46,6 +46,7 @@
#include "BKE_layer.h"
#include "BKE_screen.h"
#include "BKE_global.h"
+#include "BKE_library_override.h"
#include "BKE_node.h"
#include "BKE_text.h" /* for UI_OT_reports_to_text */
#include "BKE_report.h"
@@ -452,6 +453,215 @@ static void UI_OT_unuse_property_button(wmOperatorType *ot)
ot->flag = OPTYPE_UNDO;
}
+
+
+
+
+/* Note that we use different values for UI/UX than 'real' override operations, user does not care
+ * whether it's added or removed for the differential operation e.g. */
+enum {
+ UIOverride_Type_NOOP = 0,
+ UIOverride_Type_Replace = 1,
+ UIOverride_Type_Difference = 2, /* Add/subtract */
+ UIOverride_Type_Factor = 3, /* Multiply */
+ /* TODO: should/can we expose insert/remove ones for collections? Doubt it... */
+};
+
+static EnumPropertyItem override_type_items[] = {
+ {UIOverride_Type_NOOP, "NOOP", 0, "NoOp",
+ "'No-Operation', place holder preventing automatic override to ever affect the property"},
+ {UIOverride_Type_Replace, "REPLACE", 0, "Replace", "Completely replace value from linked data by local one"},
+ {UIOverride_Type_Difference, "DIFFERENCE", 0, "Difference", "Store difference to linked data value"},
+ {UIOverride_Type_Factor, "FACTOR", 0, "Factor", "Store factor to linked data value (useful e.g. for scale)"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+
+static int override_type_set_button_poll(bContext *C)
+{
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index;
+ bool is_overridable;
+
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
+
+ RNA_property_override_status(&ptr, prop, index, &is_overridable, NULL, NULL, NULL);
+
+ return (ptr.data && prop && is_overridable);
+}
+
+static int override_type_set_button_exec(bContext *C, wmOperator *op)
+{
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index;
+ bool created;
+ const bool all = RNA_boolean_get(op->ptr, "all");
+ const int op_type = RNA_enum_get(op->ptr, "type");
+
+ short operation;
+
+ switch (op_type) {
+ case UIOverride_Type_NOOP:
+ operation = IDOVERRIDESTATIC_OP_NOOP;
+ break;
+ case UIOverride_Type_Replace:
+ operation = IDOVERRIDESTATIC_OP_REPLACE;
+ break;
+ case UIOverride_Type_Difference:
+ operation = IDOVERRIDESTATIC_OP_ADD; /* override code will automatically switch to subtract if needed. */
+ break;
+ case UIOverride_Type_Factor:
+ operation = IDOVERRIDESTATIC_OP_MULTIPLY;
+ break;
+ default:
+ operation = IDOVERRIDESTATIC_OP_REPLACE;
+ BLI_assert(0);
+ break;
+ }
+
+ /* try to reset the nominated setting to its default value */
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
+
+ BLI_assert(ptr.id.data != NULL);
+
+ if (all) {
+ index = -1;
+ }
+
+ IDOverrideStaticPropertyOperation *opop = RNA_property_override_property_operation_get(
+ &ptr, prop, operation, index, true, NULL, &created);
+ if (!created) {
+ opop->operation = operation;
+ }
+
+ return operator_button_property_finish(C, &ptr, prop);
+}
+
+static int override_type_set_button_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ return WM_menu_invoke_ex(C, op, WM_OP_INVOKE_DEFAULT);
+}
+
+static void UI_OT_override_type_set_button(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Define Override Type";
+ ot->idname = "UI_OT_override_type_set_button";
+ ot->description = "Create an override operation, or set the type of an existing one";
+
+ /* callbacks */
+ ot->poll = override_type_set_button_poll;
+ ot->exec = override_type_set_button_exec;
+ ot->invoke = override_type_set_button_invoke;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array");
+ ot->prop = RNA_def_enum(ot->srna, "type", override_type_items, UIOverride_Type_Replace,
+ "Type", "Type of override operation");
+ /* TODO: add itemf callback, not all aoptions are available for all data types... */
+}
+
+
+static int override_remove_button_poll(bContext *C)
+{
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index;
+ bool is_overridden;
+
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
+
+ RNA_property_override_status(&ptr, prop, index, NULL, &is_overridden, NULL, NULL);
+
+ return (ptr.data && ptr.id.data && prop && is_overridden);
+}
+
+static int override_remove_button_exec(bContext *C, wmOperator *op)
+{
+ PointerRNA ptr, id_refptr, src;
+ PropertyRNA *prop;
+ int index;
+ const bool all = RNA_boolean_get(op->ptr, "all");
+
+ /* try to reset the nominated setting to its default value */
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
+
+ ID *id = ptr.id.data;
+ IDOverrideStaticProperty *oprop = RNA_property_override_property_find(&ptr, prop);
+ BLI_assert(oprop != NULL);
+ BLI_assert(id != NULL && id->override_static != NULL);
+
+ const bool is_template = (id->override_static->reference == NULL);
+
+ /* We need source (i.e. linked data) to restore values of deleted overrides...
+ * If this is an override template, we obviously do not need to restore anything. */
+ if (!is_template) {
+ RNA_id_pointer_create(id->override_static->reference, &id_refptr);
+ if (!RNA_path_resolve(&id_refptr, oprop->rna_path, &src, NULL)) {
+ BLI_assert(0 && "Failed to create matching source (linked data) RNA pointer");
+ }
+ }
+
+ if (!all && index != -1) {
+ bool is_strict_find;
+ /* Remove override operation for given item, add singular operations for the other items as needed. */
+ IDOverrideStaticPropertyOperation *opop = BKE_override_static_property_operation_find(
+ oprop, NULL, NULL, index, index, false, &is_strict_find);
+ BLI_assert(opop != NULL);
+ if (!is_strict_find) {
+ /* No specific override operation, we have to get generic one,
+ * and create item-specific override operations for all but given index, before removing generic one. */
+ for (int idx = RNA_property_array_length(&ptr, prop); idx--; ) {
+ if (idx != index) {
+ BKE_override_static_property_operation_get(oprop, opop->operation, NULL, NULL, idx, idx, true, NULL, NULL);
+ }
+ }
+ }
+ BKE_override_static_property_operation_delete(oprop, opop);
+ if (!is_template) {
+ RNA_property_copy(&ptr, &src, prop, index);
+ }
+ if (BLI_listbase_is_empty(&oprop->operations)) {
+ BKE_override_static_property_delete(id->override_static, oprop);
+ }
+ }
+ else {
+ /* Just remove whole generic override operation of this property. */
+ BKE_override_static_property_delete(id->override_static, oprop);
+ if (!is_template) {
+ RNA_property_copy(&ptr, &src, prop, -1);
+ }
+ }
+
+ return operator_button_property_finish(C, &ptr, prop);
+}
+
+static void UI_OT_override_remove_button(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Override";
+ ot->idname = "UI_OT_override_remove_button";
+ ot->description = "Remove an override operation";
+
+ /* callbacks */
+ ot->poll = override_remove_button_poll;
+ ot->exec = override_remove_button_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array");
+}
+
+
+
+
/* Copy To Selected Operator ------------------------ */
bool UI_context_copy_to_selected_list(
@@ -1243,6 +1453,8 @@ void ED_operatortypes_ui(void)
WM_operatortype_append(UI_OT_unset_property_button);
WM_operatortype_append(UI_OT_use_property_button);
WM_operatortype_append(UI_OT_unuse_property_button);
+ WM_operatortype_append(UI_OT_override_type_set_button);
+ WM_operatortype_append(UI_OT_override_remove_button);
WM_operatortype_append(UI_OT_copy_to_selected_button);
WM_operatortype_append(UI_OT_reports_to_textblock); /* XXX: temp? */
WM_operatortype_append(UI_OT_drop_color);
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index c7e1a60b05c..78874076b92 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -1075,8 +1075,10 @@ void uiTemplateSearch(
const char *newop, const char *unlinkop)
{
TemplateSearch *template_search = template_search_setup(ptr, propname, searchptr, searchpropname);
- template_search_buttons(C, layout, template_search, newop, unlinkop);
- MEM_freeN(template_search);
+ if (template_search != NULL) {
+ template_search_buttons(C, layout, template_search, newop, unlinkop);
+ MEM_freeN(template_search);
+ }
}
void uiTemplateSearchPreview(
@@ -1088,13 +1090,15 @@ void uiTemplateSearchPreview(
{
TemplateSearch *template_search = template_search_setup(ptr, propname, searchptr, searchpropname);
- template_search->use_previews = true;
- template_search->preview_rows = rows;
- template_search->preview_cols = cols;
+ if (template_search != NULL) {
+ template_search->use_previews = true;
+ template_search->preview_rows = rows;
+ template_search->preview_cols = cols;
- template_search_buttons(C, layout, template_search, newop, unlinkop);
+ template_search_buttons(C, layout, template_search, newop, unlinkop);
- MEM_freeN(template_search);
+ MEM_freeN(template_search);
+ }
}
/********************* RNA Path Builder Template ********************/
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 375f4f95697..8c894c7852e 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -1710,6 +1710,8 @@ static struct uiWidgetStateColors wcol_state_colors = {
{215, 211, 75, 255},
{180, 0, 255, 255},
{153, 0, 230, 255},
+ {74, 137, 137, 255},
+ {49, 112, 112, 255},
0.5f, 0.0f
};
@@ -2062,6 +2064,8 @@ static void widget_state(uiWidgetType *wt, int state)
widget_state_blend(wt->wcol.inner, wcol_state->inner_anim_sel, wcol_state->blend);
else if (state & UI_BUT_DRIVEN)
widget_state_blend(wt->wcol.inner, wcol_state->inner_driven_sel, wcol_state->blend);
+ else if (state & UI_BUT_OVERRIDEN)
+ widget_state_blend(wt->wcol.inner, wcol_state->inner_overridden_sel, wcol_state->blend);
copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel);
@@ -2075,6 +2079,8 @@ static void widget_state(uiWidgetType *wt, int state)
widget_state_blend(wt->wcol.inner, wcol_state->inner_anim, wcol_state->blend);
else if (state & UI_BUT_DRIVEN)
widget_state_blend(wt->wcol.inner, wcol_state->inner_driven, wcol_state->blend);
+ else if (state & UI_BUT_OVERRIDEN)
+ widget_state_blend(wt->wcol.inner, wcol_state->inner_overridden, wcol_state->blend);
if (state & UI_ACTIVE) { /* mouse over? */
wt->wcol.inner[0] = wt->wcol.inner[0] >= 240 ? 255 : wt->wcol.inner[0] + 15;
@@ -2120,7 +2126,9 @@ static void widget_state_numslider(uiWidgetType *wt, int state)
widget_state_blend(wt->wcol.item, wcol_state->inner_anim_sel, blend);
else if (state & UI_BUT_DRIVEN)
widget_state_blend(wt->wcol.item, wcol_state->inner_driven_sel, blend);
-
+ else if (state & UI_BUT_OVERRIDEN)
+ widget_state_blend(wt->wcol.item, wcol_state->inner_overridden_sel, blend);
+
if (state & UI_SELECT)
SWAP(short, wt->wcol.shadetop, wt->wcol.shadedown);
}
@@ -2131,6 +2139,8 @@ static void widget_state_numslider(uiWidgetType *wt, int state)
widget_state_blend(wt->wcol.item, wcol_state->inner_anim, blend);
else if (state & UI_BUT_DRIVEN)
widget_state_blend(wt->wcol.item, wcol_state->inner_driven, blend);
+ else if (state & UI_BUT_OVERRIDEN)
+ widget_state_blend(wt->wcol.item, wcol_state->inner_overridden, blend);
}
}
@@ -3157,7 +3167,7 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat
ui_but_v3_get(but, col);
- if (state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_REDALERT)) {
+ if (state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_OVERRIDEN | UI_BUT_REDALERT)) {
/* draw based on state - color for keyed etc */
widgetbase_draw(&wtb, wcol);
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index e541df8ffa3..d4d7d92d5ad 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -58,8 +58,7 @@
#define MVAL_PIXEL_MARGIN 5.0f
-/* until implement profile = 0 case, need to clamp somewhat above zero */
-#define PROFILE_HARD_MIN 0.15f
+#define PROFILE_HARD_MIN 0.0f
#define SEGMENTS_HARD_MAX 1000
@@ -623,6 +622,7 @@ void MESH_OT_bevel(wmOperatorType *ot)
RNA_def_enum(ot->srna, "offset_type", offset_type_items, 0, "Amount Type", "What distance Amount measures");
prop = RNA_def_float(ot->srna, "offset", 0.0f, -1e6f, 1e6f, "Amount", "", 0.0f, 1.0f);
RNA_def_property_float_array_funcs_runtime(prop, NULL, NULL, mesh_ot_bevel_offset_range_func);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
RNA_def_int(ot->srna, "segments", 1, 1, SEGMENTS_HARD_MAX, "Segments", "Segments for curved edge", 1, 8);
RNA_def_float(ot->srna, "profile", 0.5f, PROFILE_HARD_MIN, 1.0f, "Profile",
"Controls profile shape (0.5 = round)", PROFILE_HARD_MIN, 1.0f);
diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c
index 3e0747f055f..afe52ec69f4 100644
--- a/source/blender/editors/mesh/editmesh_inset.c
+++ b/source/blender/editors/mesh/editmesh_inset.c
@@ -80,8 +80,10 @@ static void edbm_inset_update_header(wmOperator *op, bContext *C)
{
InsetData *opdata = op->customdata;
- const char *str = IFACE_("Confirm: Enter/LClick, Cancel: (Esc/RClick), Thickness: %s, "
- "Depth (Ctrl to tweak): %s (%s), Outset (O): (%s), Boundary (B): (%s), Individual (I): (%s)");
+ const char *str = IFACE_(
+ "Confirm: Enter/LClick, Cancel: (Esc/RClick), Thickness: %s, "
+ "Depth (Ctrl to tweak): %s (%s), Outset (O): (%s), Boundary (B): (%s), Individual (I): (%s)"
+ );
char msg[UI_MAX_DRAW_STR];
ScrArea *sa = CTX_wm_area(C);
@@ -141,7 +143,8 @@ static bool edbm_inset_init(bContext *C, wmOperator *op, const bool is_modal)
ARegion *ar = CTX_wm_region(C);
opdata->mesh_backup = EDBM_redo_state_store(em);
- opdata->draw_handle_pixel = ED_region_draw_cb_activate(ar->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL);
+ opdata->draw_handle_pixel = ED_region_draw_cb_activate(
+ ar->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL);
G.moving = G_TRANSFORM_EDIT;
if (v3d) {
opdata->twtype = v3d->twtype;
@@ -506,16 +509,27 @@ void MESH_OT_inset(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING;
/* properties */
- RNA_def_boolean(ot->srna, "use_boundary", true, "Boundary", "Inset face boundaries");
- RNA_def_boolean(ot->srna, "use_even_offset", true, "Offset Even", "Scale the offset to give more even thickness");
- RNA_def_boolean(ot->srna, "use_relative_offset", false, "Offset Relative", "Scale the offset by surrounding geometry");
- RNA_def_boolean(ot->srna, "use_edge_rail", false, "Edge Rail", "Inset the region along existing edges");
+ RNA_def_boolean(
+ ot->srna, "use_boundary",
+ true, "Boundary", "Inset face boundaries");
+ RNA_def_boolean(
+ ot->srna, "use_even_offset",
+ true, "Offset Even", "Scale the offset to give more even thickness");
+ RNA_def_boolean(
+ ot->srna, "use_relative_offset",
+ false, "Offset Relative", "Scale the offset by surrounding geometry");
+ RNA_def_boolean(
+ ot->srna, "use_edge_rail",
+ false, "Edge Rail", "Inset the region along existing edges");
prop = RNA_def_float_distance(ot->srna, "thickness", 0.01f, 0.0f, 1e12f, "Thickness", "", 0.0f, 10.0f);
/* use 1 rather then 10 for max else dragging the button moves too far */
RNA_def_property_ui_range(prop, 0.0, 1.0, 0.01, 4);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
prop = RNA_def_float_distance(ot->srna, "depth", 0.0f, -1e12f, 1e12f, "Depth", "", -10.0f, 10.0f);
RNA_def_property_ui_range(prop, -10.0f, 10.0f, 0.01, 4);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
RNA_def_boolean(ot->srna, "use_outset", false, "Outset", "Outset rather than inset");
RNA_def_boolean(ot->srna, "use_select_inset", false, "Select Outer", "Select the new inset faces");
diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c
index 876d63ef64a..3ab56f2ebcb 100644
--- a/source/blender/editors/mesh/editmesh_loopcut.c
+++ b/source/blender/editors/mesh/editmesh_loopcut.c
@@ -534,9 +534,6 @@ static int ringsel_init(bContext *C, wmOperator *op, bool do_cut)
lcd->num.unit_type[0] = B_UNIT_NONE;
lcd->num.unit_type[1] = B_UNIT_NONE;
- /* XXX, temp, workaround for [# ] */
- EDBM_mesh_ensure_valid_dm_hack(scene, lcd->em);
-
em_setup_viewcontext(C, &lcd->vc);
ED_region_tag_redraw(lcd->ar);
diff --git a/source/blender/editors/mesh/editmesh_polybuild.c b/source/blender/editors/mesh/editmesh_polybuild.c
index bfabd64396f..f398f087da9 100644
--- a/source/blender/editors/mesh/editmesh_polybuild.c
+++ b/source/blender/editors/mesh/editmesh_polybuild.c
@@ -132,7 +132,7 @@ static int edbm_polybuild_face_at_cursor_invoke(
BMEdge *e_iter = v_act->e;
do {
if ((BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN) == false) &&
- (allow_wire ? BM_edge_is_wire(e_iter) : BM_edge_is_boundary(e_iter)))
+ (allow_wire ? BM_edge_is_wire(e_iter) : BM_edge_is_boundary(e_iter)))
{
if (i == 2) {
e_pair[0] = e_pair[1] = NULL;
@@ -489,9 +489,9 @@ static int edbm_polybuild_hover_invoke(
/* pass */
}
else if (vc.win->tweak ||
- (vc.win->eventstate->check_click &&
- vc.win->eventstate->prevval == KM_PRESS &&
- ISMOUSE(vc.win->eventstate->prevtype)))
+ (vc.win->eventstate->check_click &&
+ vc.win->eventstate->prevval == KM_PRESS &&
+ ISMOUSE(vc.win->eventstate->prevtype)))
{
return OPERATOR_PASS_THROUGH;
}
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index 0a0a8ff2de3..3e0afd3095e 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -640,9 +640,17 @@ BMEdge *EDBM_edge_find_nearest_ex(
unsigned int index;
BMEdge *eed;
+ /* Make sure that the edges also are considered to find nearest.
+ * TODO: cleanup: add `selectmode` as a parameter */
+ const short ts_selectmode = vc->scene->toolsettings->selectmode;
+ vc->scene->toolsettings->selectmode |= SCE_SELECT_EDGE;
+
/* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */
ED_view3d_backbuf_validate(eval_ctx, vc);
+ /* restore `selectmode` */
+ vc->scene->toolsettings->selectmode = ts_selectmode;
+
index = ED_view3d_backbuf_sample_rect(eval_ctx, vc, vc->mval, dist_px, bm_solidoffs, bm_wireoffs, &dist_test);
eed = index ? BM_edge_at_index_find_or_table(bm, index - 1) : NULL;
@@ -1583,9 +1591,17 @@ static bool mouse_mesh_loop(bContext *C, const int mval[2], bool extend, bool de
mvalf[1] = (float)(vc.mval[1] = mval[1]);
em = vc.em;
+ /* Make sure that the edges are also considered for selection.
+ * TODO: cleanup: add `selectmode` as a parameter */
+ const short ts_selectmode = vc.scene->toolsettings->selectmode;
+ vc.scene->toolsettings->selectmode |= SCE_SELECT_EDGE;
+
/* no afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad */
ED_view3d_backbuf_validate(&eval_ctx, &vc);
+ /* restore `selectmode` */
+ vc.scene->toolsettings->selectmode = ts_selectmode;
+
eed = EDBM_edge_find_nearest_ex(&eval_ctx, &vc, &dist, NULL, true, true, NULL);
if (eed == NULL) {
return false;
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 74bd4e978e7..75a13a916e6 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -311,7 +311,7 @@ void EMBM_project_snap_verts(bContext *C, ARegion *ar, BMEditMesh *em)
ED_view3d_init_mats_rv3d(obedit, ar->regiondata);
struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d(
- CTX_data_main(C), CTX_data_scene(C), CTX_data_view_layer(C), CTX_data_engine(C), 0,
+ CTX_data_main(C), CTX_data_scene(C), CTX_data_view_layer(C), CTX_data_engine_type(C), 0,
ar, CTX_wm_view3d(C));
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index 230f46abad1..27fe93b049a 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -53,7 +53,7 @@
#include "DEG_depsgraph.h"
-#include "BKE_object.h" /* XXX. only for EDBM_mesh_ensure_valid_dm_hack() which will be removed */
+#include "BKE_object.h" /* XXX. only for EDBM_mesh_load(). */
#include "WM_api.h"
#include "WM_types.h"
@@ -108,21 +108,6 @@ void EDBM_redo_state_free(BMBackup *backup, BMEditMesh *em, int recalctess)
BKE_editmesh_tessface_calc(em);
}
-/* hack to workaround multiple operators being called within the same event loop without an update
- * see: [#31811] */
-void EDBM_mesh_ensure_valid_dm_hack(Scene *scene, BMEditMesh *em)
-{
- if ((((ID *)em->ob->data)->tag & LIB_TAG_ID_RECALC) ||
- (em->ob->recalc & OB_RECALC_DATA))
- {
- /* since we may not have done selection flushing */
- if ((em->ob->recalc & OB_RECALC_DATA) == 0) {
- DEG_id_tag_update(&em->ob->id, OB_RECALC_DATA);
- }
- BKE_object_handle_update(G.main->eval_ctx, scene, em->ob);
- }
-}
-
void EDBM_mesh_normals_update(BMEditMesh *em)
{
BM_mesh_normals_update(em->bm);
@@ -413,6 +398,7 @@ void EDBM_mesh_load(Object *ob)
* of freed data on scene update, especially in cases when there are dependency
* cycles.
*/
+ /*
for (Object *other_object = G.main->object.first;
other_object != NULL;
other_object = other_object->id.next)
@@ -421,6 +407,7 @@ void EDBM_mesh_load(Object *ob)
BKE_object_free_derived_caches(other_object);
}
}
+ */
}
/**
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 77b30951dee..e8807432328 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -449,10 +449,13 @@ Object *ED_object_add_type(
ob->gameflag &= ~(OB_SENSOR | OB_RIGID_BODY | OB_SOFT_BODY | OB_COLLISION | OB_CHARACTER | OB_OCCLUDER | OB_DYNAMIC | OB_NAVMESH); /* copied from rna_object.c */
}
+ /* TODO(sergey): This is weird to manually tag objects for update, better to
+ * use DEG_id_tag_update here perhaps.
+ */
DEG_id_type_tag(bmain, ID_OB);
DEG_relations_tag_update(bmain);
- if (ob->data) {
- ED_render_id_flush_update(bmain, ob->data);
+ if (ob->data != NULL) {
+ DEG_id_tag_update_ex(bmain, (ID *)ob->data, DEG_TAG_EDITORS_UPDATE);
}
if (enter_editmode)
@@ -1218,7 +1221,7 @@ void ED_object_base_free_and_unlink(Main *bmain, Scene *scene, Object *ob)
DEG_id_tag_update_ex(bmain, &ob->id, DEG_TAG_BASE_FLAGS_UPDATE);
object_delete_check_glsl_update(ob);
- BKE_collections_object_remove(bmain, scene, ob, true);
+ BKE_collections_object_remove(bmain, &scene->id, ob, true);
}
static int object_delete_exec(bContext *C, wmOperator *op)
@@ -2340,8 +2343,8 @@ Base *ED_object_add_duplicate(Main *bmain, Scene *scene, ViewLayer *view_layer,
/* DAG_relations_tag_update(bmain); */ /* caller must do */
- if (ob->data) {
- ED_render_id_flush_update(bmain, ob->data);
+ if (ob->data != NULL) {
+ DEG_id_tag_update_ex(bmain, (ID *)ob->data, DEG_TAG_EDITORS_UPDATE);
}
BKE_main_id_clear_newpoins(bmain);
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index 804d0ed1f0d..5697c48d381 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -1516,15 +1516,13 @@ bool ED_object_mode_compat_set(bContext *C, Object *ob, int mode, ReportList *re
{
bool ok;
if (!ELEM(ob->mode, mode, OB_MODE_OBJECT)) {
- WorkSpace *workspace = CTX_wm_workspace(C);
const char *opstring = object_mode_op_string(ob->mode);
WM_operator_name_call(C, opstring, WM_OP_EXEC_REGION_WIN, NULL);
#ifdef USE_WORKSPACE_MODE
- BKE_workspace_object_mode_set(workspace, ob->mode);
-#else
- UNUSED_VARS(workspace);
+ BKE_workspace_object_mode_set(CTX_wm_workspace(C), CTX_data_scene(C), ob->mode);
#endif
+
ok = ELEM(ob->mode, mode, OB_MODE_OBJECT);
if (!ok) {
wmOperatorType *ot = WM_operatortype_find(opstring, false);
@@ -1648,7 +1646,7 @@ void ED_object_toggle_modes(bContext *C, int mode)
#ifdef USE_WORKSPACE_MODE
Object *ob = CTX_data_active_object(C);
if (ob) {
- BKE_workspace_object_mode_set(workspace, ob->mode);
+ BKE_workspace_object_mode_set(workspace, CTX_data_scene(C), ob->mode);
}
#endif
}
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index 3e655fa04a4..c38a7d58904 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -68,6 +68,7 @@ void OBJECT_OT_track_clear(struct wmOperatorType *ot);
void OBJECT_OT_slow_parent_set(struct wmOperatorType *ot);
void OBJECT_OT_slow_parent_clear(struct wmOperatorType *ot);
void OBJECT_OT_make_local(struct wmOperatorType *ot);
+void OBJECT_OT_make_override(struct wmOperatorType *ot);
void OBJECT_OT_make_single_user(struct wmOperatorType *ot);
void OBJECT_OT_make_links_scene(struct wmOperatorType *ot);
void OBJECT_OT_make_links_data(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index c87df877d5c..ceea3b9c0ac 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -84,6 +84,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_slow_parent_set);
WM_operatortype_append(OBJECT_OT_slow_parent_clear);
WM_operatortype_append(OBJECT_OT_make_local);
+ WM_operatortype_append(OBJECT_OT_make_override);
WM_operatortype_append(OBJECT_OT_make_single_user);
WM_operatortype_append(OBJECT_OT_make_links_scene);
WM_operatortype_append(OBJECT_OT_make_links_data);
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 9854b61813b..436364ec6c3 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -77,8 +77,10 @@
#include "BKE_lattice.h"
#include "BKE_layer.h"
#include "BKE_library.h"
+#include "BKE_library_override.h"
#include "BKE_library_query.h"
#include "BKE_library_remap.h"
+#include "BKE_lightprobe.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_mball.h"
@@ -340,17 +342,15 @@ static int make_proxy_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Object *ob, *gob = ED_object_active_context(C);
- GroupObject *go;
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
if (gob->dup_group != NULL) {
- go = BLI_findlink(&gob->dup_group->gobject, RNA_enum_get(op->ptr, "object"));
- ob = go->ob;
+ Base *base = BLI_findlink(&gob->dup_group->view_layer->object_bases, RNA_enum_get(op->ptr, "object"));
+ ob = base->object;
}
else {
ob = gob;
- gob = NULL;
}
if (ob) {
@@ -395,17 +395,18 @@ static const EnumPropertyItem *proxy_group_object_itemf(bContext *C, PointerRNA
int totitem = 0;
int i = 0;
Object *ob = ED_object_active_context(C);
- GroupObject *go;
if (!ob || !ob->dup_group)
return DummyRNA_DEFAULT_items;
/* find the object to affect */
- for (go = ob->dup_group->gobject.first; go; go = go->next) {
- item_tmp.identifier = item_tmp.name = go->ob->id.name + 2;
+ FOREACH_GROUP_OBJECT(ob->dup_group, object)
+ {
+ item_tmp.identifier = item_tmp.name = object->id.name + 2;
item_tmp.value = i++;
RNA_enum_item_add(&item, &totitem, &item_tmp);
}
+ FOREACH_GROUP_OBJECT_END
RNA_enum_item_end(&item, &totitem);
*r_free = true;
@@ -1366,10 +1367,10 @@ static int make_links_scene_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- SceneCollection *sc_to = BKE_collection_master(scene_to);
+ SceneCollection *sc_to = BKE_collection_master(&scene_to->id);
CTX_DATA_BEGIN (C, Base *, base, selected_bases)
{
- BKE_collection_object_add(scene_to, sc_to, base->object);
+ BKE_collection_object_add(&scene_to->id, sc_to, base->object);
}
CTX_DATA_END;
@@ -1689,12 +1690,11 @@ static void single_object_users_scene_collection(Main *bmain, Scene *scene, Scen
static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const int flag, const bool copy_groups)
{
Group *group, *groupn;
- GroupObject *go;
clear_sca_new_poins(); /* BGE logic */
/* duplicate all the objects of the scene */
- SceneCollection *msc = BKE_collection_master(scene);
+ SceneCollection *msc = BKE_collection_master(&scene->id);
single_object_users_scene_collection(bmain, scene, msc, flag, copy_groups);
/* loop over ViewLayers and assign the pointers accordingly */
@@ -1706,22 +1706,26 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in
/* duplicate groups that consist entirely of duplicated objects */
for (group = bmain->group.first; group; group = group->id.next) {
- if (copy_groups && group->gobject.first) {
+ if (copy_groups && group->view_layer->object_bases.first) {
bool all_duplicated = true;
- for (go = group->gobject.first; go; go = go->next) {
- if (!(go->ob && (go->ob->id.newid))) {
+ FOREACH_GROUP_OBJECT(group, object)
+ {
+ if (object->id.newid == NULL) {
all_duplicated = false;
break;
}
}
+ FOREACH_GROUP_OBJECT_END
if (all_duplicated) {
groupn = ID_NEW_SET(group, BKE_group_copy(bmain, group));
- for (go = groupn->gobject.first; go; go = go->next) {
- go->ob = (Object *)go->ob->id.newid;
+ FOREACH_GROUP_BASE(groupn, base)
+ {
+ base->object = (Object *)base->object->id.newid;
}
+ FOREACH_GROUP_BASE_END
}
}
}
@@ -1840,9 +1844,15 @@ static void single_obdata_users(Main *bmain, Scene *scene, ViewLayer *view_layer
case OB_SPEAKER:
ob->data = ID_NEW_SET(ob->data, BKE_speaker_copy(bmain, ob->data));
break;
+ case OB_LIGHTPROBE:
+ ob->data = ID_NEW_SET(ob->data, BKE_lightprobe_copy(bmain, ob->data));
+ break;
default:
- if (G.debug & G_DEBUG)
- printf("ERROR %s: can't copy %s\n", __func__, id->name);
+ printf("ERROR %s: can't copy %s\n", __func__, id->name);
+ BLI_assert(!"This should never happen.");
+
+ /* We need to end the FOREACH_OBJECT_FLAG iterator to prevent memory leak. */
+ BKE_scene_objects_iterator_end(&iter_macro);
return;
}
@@ -2143,7 +2153,7 @@ static bool make_local_all__instance_indirect_unused(Main *bmain, Scene *scene,
id_us_plus(&ob->id);
- BKE_collection_object_add(scene, sc, ob);
+ BKE_collection_object_add(&scene->id, sc, ob);
base = BKE_view_layer_base_find(view_layer, ob);
base->flag |= BASE_SELECTED;
BKE_scene_object_base_flag_sync_from_base(base);
@@ -2325,6 +2335,44 @@ void OBJECT_OT_make_local(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "");
}
+static int make_override_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Main *bmain = CTX_data_main(C);
+ Object *locobj, *refobj = CTX_data_active_object(C);
+
+ locobj = (Object *)BKE_override_static_create_from(bmain, &refobj->id);
+ UNUSED_VARS(locobj);
+
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+static int make_override_poll(bContext *C)
+{
+ Object *obact = CTX_data_active_object(C);
+
+ /* Object must be directly linked to be overridable. */
+ return (ED_operator_objectmode(C) && obact && obact->id.lib != NULL && obact->id.tag & LIB_TAG_EXTERN);
+}
+
+void OBJECT_OT_make_override(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Make Override";
+ ot->description = "Make local override of this library linked data-block";
+ ot->idname = "OBJECT_OT_make_override";
+
+ /* api callbacks */
+ ot->exec = make_override_exec;
+ ot->poll = make_override_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+}
+
enum {
MAKE_SINGLE_USER_ALL = 1,
MAKE_SINGLE_USER_SELECTED = 2,
diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c
index 47e63cb43e5..552380cebdb 100644
--- a/source/blender/editors/object/object_select.c
+++ b/source/blender/editors/object/object_select.c
@@ -123,8 +123,7 @@ void ED_object_base_activate(bContext *C, Base *base)
if (base) {
#ifdef USE_WORKSPACE_MODE
- WorkSpace *workspace = CTX_wm_workspace(C);
- BKE_workspace_object_mode_set(workspace, base->object->mode);
+ BKE_workspace_object_mode_set(CTX_wm_workspace(C), CTX_data_scene(C), base->object->mode);
#endif
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, view_layer);
}
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index 2c659d2b985..4e75ca3e6f1 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -832,7 +832,7 @@ static void clean_viewport_memory(Main *bmain, Scene *scene)
}
}
- for (SETLOOPER_SET_ONLY(scene, sce_iter, base)) {
+ for (SETLOOPER_SET_ONLY(scene, sce_iter, base)) {
clean_viewport_memory_base(base);
}
}
diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c
index 8956ef79958..a391b13a000 100644
--- a/source/blender/editors/render/render_update.c
+++ b/source/blender/editors/render/render_update.c
@@ -70,6 +70,8 @@
#include "ED_render.h"
#include "ED_view3d.h"
+#include "DEG_depsgraph.h"
+
#include "WM_api.h"
#include "render_intern.h" // own include
@@ -78,10 +80,13 @@ extern Material defmaterial;
/***************************** Render Engines ********************************/
-void ED_render_scene_update(Main *bmain, Scene *scene, int updated)
+void ED_render_scene_update(const DEGEditorUpdateContext *update_ctx, int updated)
{
/* viewport rendering update on data changes, happens after depsgraph
* updates if there was any change. context is set to the 3d view */
+ Main *bmain = update_ctx->bmain;
+ Scene *scene = update_ctx->scene;
+ ViewLayer *view_layer = update_ctx->view_layer;
bContext *C;
wmWindowManager *wm;
wmWindow *win;
@@ -123,15 +128,11 @@ void ED_render_scene_update(Main *bmain, Scene *scene, int updated)
continue;
for (ar = sa->regionbase.first; ar; ar = ar->next) {
- RegionView3D *rv3d;
- RenderEngine *engine;
-
- if (ar->regiontype != RGN_TYPE_WINDOW)
+ if (ar->regiontype != RGN_TYPE_WINDOW) {
continue;
-
- rv3d = ar->regiondata;
- engine = rv3d->render_engine;
-
+ }
+ RegionView3D *rv3d = ar->regiondata;
+ RenderEngine *engine = rv3d->render_engine;
/* call update if the scene changed, or if the render engine
* tagged itself for update (e.g. because it was busy at the
* time of the last update) */
@@ -145,13 +146,20 @@ void ED_render_scene_update(Main *bmain, Scene *scene, int updated)
engine->type->view_update(engine, C);
}
- else if ((RE_engines_find(view_render->engine_id)->flag & RE_USE_LEGACY_PIPELINE) == 0) {
- if (updated) {
- CTX_wm_screen_set(C, sc);
- CTX_wm_area_set(C, sa);
- CTX_wm_region_set(C, ar);
-
- DRW_notify_view_update(C);
+ else {
+ RenderEngineType *engine_type = RE_engines_find(view_render->engine_id);
+ if ((engine_type->flag & RE_USE_LEGACY_PIPELINE) == 0) {
+ if (updated) {
+ DRW_notify_view_update(
+ (&(DRWUpdateContext){
+ .bmain = bmain,
+ .scene = scene,
+ .view_layer = view_layer,
+ .ar = ar,
+ .v3d = (View3D *)sa->spacedata.first,
+ .engine_type = engine_type
+ }));
+ }
}
}
}
@@ -163,23 +171,6 @@ void ED_render_scene_update(Main *bmain, Scene *scene, int updated)
recursive_check = false;
}
-void ED_render_scene_update_pre(Main *bmain, Scene *scene, bool time)
-{
- /* Blender internal might access to the data which is gonna to be freed
- * by the scene update functions. This applies for example to simulation
- * data like smoke and fire.
- */
- if (time && !BKE_scene_use_new_shading_nodes(scene)) {
- bScreen *sc;
- ScrArea *sa;
- for (sc = bmain->screen.first; sc; sc = sc->id.next) {
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- ED_render_engine_area_exit(bmain, sa);
- }
- }
- }
-}
-
void ED_render_engine_area_exit(Main *bmain, ScrArea *sa)
{
/* clear all render engines in this area */
@@ -199,18 +190,21 @@ void ED_render_engine_area_exit(Main *bmain, ScrArea *sa)
void ED_render_engine_changed(Main *bmain)
{
/* on changing the render engine type, clear all running render engines */
- bScreen *sc;
- ScrArea *sa;
- Scene *scene;
-
- for (sc = bmain->screen.first; sc; sc = sc->id.next)
- for (sa = sc->areabase.first; sa; sa = sa->next)
+ for (bScreen *sc = bmain->screen.first; sc; sc = sc->id.next) {
+ for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
ED_render_engine_area_exit(bmain, sa);
-
+ }
+ }
RE_FreePersistentData();
-
- for (scene = bmain->scene.first; scene; scene = scene->id.next) {
- ED_render_id_flush_update(bmain, &scene->id);
+ /* Inform all render engines and draw managers. */
+ DEGEditorUpdateContext update_ctx = {NULL};
+ update_ctx.bmain = bmain;
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ update_ctx.scene = scene;
+ LINKLIST_FOREACH(ViewLayer *, view_layer, &scene->view_layers) {
+ update_ctx.view_layer = view_layer;
+ ED_render_id_flush_update(&update_ctx, &scene->id);
+ }
if (scene->nodetree) {
ntreeCompositUpdateRLayers(scene->nodetree);
}
@@ -536,14 +530,18 @@ static void scene_changed(Main *bmain, Scene *scene)
}
}
-void ED_render_id_flush_update(Main *bmain, ID *id)
+void ED_render_id_flush_update(const DEGEditorUpdateContext *update_ctx, ID *id)
{
/* this can be called from render or baking thread when a python script makes
* changes, in that case we don't want to do any editor updates, and making
* GPU changes is not possible because OpenGL only works in the main thread */
- if (!BLI_thread_is_main())
+ if (!BLI_thread_is_main()) {
return;
-
+ }
+ Main *bmain = update_ctx->bmain;
+ Scene *scene = update_ctx->scene;
+ ViewLayer *view_layer = update_ctx->view_layer;
+ /* Internal ID update handlers. */
switch (GS(id->name)) {
case ID_MA:
material_changed(bmain, (Material *)id);
@@ -569,7 +567,42 @@ void ED_render_id_flush_update(Main *bmain, ID *id)
render_engine_flag_changed(bmain, RE_ENGINE_UPDATE_OTHER);
break;
}
-
+ /* Inform all draw managers about changes.
+ *
+ * TODO(sergey): This code is run for every updated ID, via flushing
+ * mechanism. How can we avoid iterating over the whole interface for
+ * every of those IDs? One of the ideas would be to call draw manager's
+ * ID update which is not bound to any of contexts.
+ */
+ {
+ wmWindowManager *wm = bmain->wm.first;
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ bScreen *sc = WM_window_get_active_screen(win);
+ WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
+ ViewRender *view_render = BKE_viewrender_get(win->scene, workspace);
+ for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
+ if (sa->spacetype != SPACE_VIEW3D) {
+ continue;
+ }
+ for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->regiontype != RGN_TYPE_WINDOW) {
+ continue;
+ }
+ RenderEngineType *engine_type = RE_engines_find(view_render->engine_id);
+ DRW_notify_id_update(
+ (&(DRWUpdateContext){
+ .bmain = bmain,
+ .scene = scene,
+ .view_layer = view_layer,
+ .ar = ar,
+ .v3d = (View3D *)sa->spacedata.first,
+ .engine_type = engine_type
+ }),
+ id);
+ }
+ }
+ }
+ }
}
diff --git a/source/blender/editors/scene/scene_edit.c b/source/blender/editors/scene/scene_edit.c
index c7f04a0e2f9..812f9a736bf 100644
--- a/source/blender/editors/scene/scene_edit.c
+++ b/source/blender/editors/scene/scene_edit.c
@@ -118,16 +118,20 @@ void ED_scene_exit(bContext *C)
ED_object_editmode_exit(C, EM_FREEDATA | EM_DO_UNDO);
}
+static ViewLayer *scene_change_get_new_view_layer(const WorkSpace *workspace, const Scene *scene_new)
+{
+ ViewLayer *layer_new = BKE_workspace_view_layer_get(workspace, scene_new);
+ return layer_new ? layer_new : BKE_view_layer_from_scene_get(scene_new);
+}
+
void ED_scene_changed_update(Main *bmain, bContext *C, Scene *scene_new, const bScreen *active_screen)
{
- /* XXX Just using active scene render-layer for workspace when switching,
- * but workspace should remember the last one set. Could store render-layer
- * per window-workspace combination (using WorkSpaceDataRelation) */
- ViewLayer *layer_new = BLI_findlink(&scene_new->view_layers, scene_new->active_view_layer);
+ WorkSpace *workspace = CTX_wm_workspace(C);
+ ViewLayer *layer_new = scene_change_get_new_view_layer(workspace, scene_new);
Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene_new, layer_new, true);
CTX_data_scene_set(C, scene_new);
- BKE_workspace_view_layer_set(CTX_wm_workspace(C), layer_new);
+ BKE_workspace_view_layer_set(workspace, layer_new, scene_new);
BKE_scene_set_background(bmain, scene_new);
DEG_graph_relations_update(depsgraph, bmain, scene_new, layer_new);
DEG_on_visible_update(bmain, false);
@@ -186,7 +190,8 @@ bool ED_scene_view_layer_delete(
BLI_assert(BLI_listbase_is_empty(&scene->view_layers) == false);
scene->active_view_layer = 0;
- ED_workspace_view_layer_unset(bmain, layer, scene->view_layers.first);
+ ED_workspace_view_layer_unset(bmain, scene, layer, scene->view_layers.first);
+ BKE_workspace_view_layer_remove_references(bmain, layer);
view_layer_remove_unset_nodetrees(bmain, scene, layer);
BKE_view_layer_free(layer);
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index e5ed2ff1d67..dbeac782e10 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -51,6 +51,7 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
#include "wm_subwindow.h"
#include "ED_screen.h"
@@ -511,6 +512,33 @@ void ED_region_set(const bContext *C, ARegion *ar)
ED_region_pixelspace(ar);
}
+/* Follow wmMsgNotifyFn spec */
+void ED_region_do_msg_notify_tag_redraw(
+ bContext *UNUSED(C), wmMsgSubscribeKey *UNUSED(msg_key), wmMsgSubscribeValue *msg_val)
+{
+ ARegion *ar = msg_val->owner;
+ ED_region_tag_redraw(ar);
+
+ /* This avoids _many_ situations where header/properties control display settings.
+ * the common case is space properties in the header */
+ if (ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_UI)) {
+ while (ar && ar->prev) {
+ ar = ar->prev;
+ }
+ for (; ar; ar = ar->next) {
+ if (ELEM(ar->regiontype, RGN_TYPE_WINDOW, RGN_TYPE_CHANNELS)) {
+ ED_region_tag_redraw(ar);
+ }
+ }
+ }
+}
+/* Follow wmMsgNotifyFn spec */
+void ED_area_do_msg_notify_tag_refresh(
+ bContext *UNUSED(C), wmMsgSubscribeKey *UNUSED(msg_key), wmMsgSubscribeValue *msg_val)
+{
+ ScrArea *sa = msg_val->user_data;
+ ED_area_tag_refresh(sa);
+}
/* only exported for WM */
void ED_region_do_draw(bContext *C, ARegion *ar)
@@ -589,6 +617,37 @@ void ED_region_do_draw(bContext *C, ARegion *ar)
region_draw_emboss(ar, &ar->winrct);
}
}
+
+ /* We may want to detach message-subscriptions from drawing. */
+ {
+ WorkSpace *workspace = CTX_wm_workspace(C);
+ wmWindowManager *wm = CTX_wm_manager(C);
+ bScreen *screen = WM_window_get_active_screen(win);
+ Scene *scene = CTX_data_scene(C);
+ struct wmMsgBus *mbus = wm->message_bus;
+ WM_msgbus_clear_by_owner(mbus, ar);
+
+ /* Cheat, always subscribe to this space type properties.
+ *
+ * This covers most cases and avoids copy-paste similar code for each space type.
+ */
+ if (ELEM(ar->regiontype, RGN_TYPE_WINDOW, RGN_TYPE_CHANNELS, RGN_TYPE_UI, RGN_TYPE_TOOLS)) {
+ SpaceLink *sl = sa->spacedata.first;
+
+ PointerRNA ptr;
+ RNA_pointer_create(&screen->id, &RNA_Space, sl, &ptr);
+
+ wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
+ .owner = ar,
+ .user_data = ar,
+ .notify = ED_region_do_msg_notify_tag_redraw,
+ };
+ /* All properties for this space type. */
+ WM_msg_subscribe_rna(mbus, &ptr, NULL, &msg_sub_value_region_tag_redraw, __func__);
+ }
+
+ ED_region_message_subscribe(C, workspace, scene, screen, sa, ar, mbus);
+ }
}
/* **********************************
@@ -2695,3 +2754,25 @@ void ED_region_cache_draw_cached_segments(const ARegion *ar, const int num_segme
immUnbindProgram();
}
}
+
+/**
+ * Generate subscriptions for this region.
+ */
+void ED_region_message_subscribe(
+ bContext *C,
+ struct WorkSpace *workspace, struct Scene *scene,
+ struct bScreen *screen, struct ScrArea *sa, struct ARegion *ar,
+ struct wmMsgBus *mbus)
+{
+ if (ar->manipulator_map != NULL) {
+ WM_manipulatormap_message_subscribe(C, ar->manipulator_map, ar, mbus);
+ }
+
+ if (BLI_listbase_is_empty(&ar->uiblocks)) {
+ UI_region_message_subscribe(ar, mbus);
+ }
+
+ if (ar->type->message_subscribe != NULL) {
+ ar->type->message_subscribe(C, workspace, scene, screen, sa, ar, mbus);
+ }
+}
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index d84f256bc32..4c62253bef6 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -91,7 +91,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
ViewLayer *view_layer = BKE_view_layer_from_workspace_get(scene, workspace);
Object *obedit = scene->obedit;
- Object *obact = view_layer->basact ? view_layer->basact->object : NULL;
+ Object *obact = (view_layer && view_layer->basact) ? view_layer->basact->object : NULL;
if (CTX_data_dir(member)) {
CTX_data_dir_set(result, screen_context_dir);
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index c1ea219ad04..4b5ce2f4b81 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -66,6 +66,8 @@
#include "UI_interface.h"
+#include "WM_message.h"
+
/* XXX actually should be not here... solve later */
#include "wm_subwindow.h"
@@ -897,6 +899,8 @@ void ED_region_exit(bContext *C, ARegion *ar)
ar->regiontimer = NULL;
}
+ WM_msgbus_clear_by_owner(wm->message_bus, ar);
+
CTX_wm_region_set(C, prevar);
}
diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c
index fb113816144..da9cb69b528 100644
--- a/source/blender/editors/screen/workspace_edit.c
+++ b/source/blender/editors/screen/workspace_edit.c
@@ -71,15 +71,16 @@
* \{ */
WorkSpace *ED_workspace_add(
- Main *bmain, const char *name, ViewLayer *act_view_layer, ViewRender *view_render)
+ Main *bmain, const char *name, Scene *scene,
+ ViewLayer *act_view_layer, ViewRender *view_render)
{
WorkSpace *workspace = BKE_workspace_add(bmain, name);
- BKE_workspace_view_layer_set(workspace, act_view_layer);
+ BKE_workspace_view_layer_set(workspace, act_view_layer, scene);
BKE_viewrender_copy(&workspace->view_render, view_render);
#ifdef USE_WORKSPACE_MODE
- BKE_workspace_object_mode_set(workspace, OB_MODE_OBJECT);
+ BKE_workspace_object_mode_set(workspace, scene, OB_MODE_OBJECT);
#endif
return workspace;
@@ -94,8 +95,9 @@ static void workspace_change_update_mode(
const WorkSpace *workspace_old, const WorkSpace *workspace_new,
bContext *C, Object *ob_act, ReportList *reports)
{
- eObjectMode mode_old = BKE_workspace_object_mode_get(workspace_old);
- eObjectMode mode_new = BKE_workspace_object_mode_get(workspace_new);
+ const Scene *scene = CTX_data_scene(C);
+ eObjectMode mode_old = BKE_workspace_object_mode_get(workspace_old, scene);
+ eObjectMode mode_new = BKE_workspace_object_mode_get(workspace_new, scene);
if (mode_old != mode_new) {
ED_object_mode_compat_set(C, ob_act, mode_new, reports);
@@ -105,10 +107,11 @@ static void workspace_change_update_mode(
#endif
static void workspace_change_update_view_layer(
- WorkSpace *workspace_new, const WorkSpace *workspace_old)
+ WorkSpace *workspace_new, const WorkSpace *workspace_old,
+ Scene *scene)
{
- if (!BKE_workspace_view_layer_get(workspace_new)) {
- BKE_workspace_view_layer_set(workspace_new, BKE_workspace_view_layer_get(workspace_old));
+ if (!BKE_workspace_view_layer_get(workspace_new, scene)) {
+ BKE_workspace_view_layer_set(workspace_new, BKE_workspace_view_layer_get(workspace_old, scene), scene);
}
}
@@ -117,7 +120,7 @@ static void workspace_change_update(
bContext *C, wmWindowManager *wm)
{
/* needs to be done before changing mode! (to ensure right context) */
- workspace_change_update_view_layer(workspace_new, workspace_old);
+ workspace_change_update_view_layer(workspace_new, workspace_old, CTX_data_scene(C));
#ifdef USE_WORKSPACE_MODE
workspace_change_update_mode(workspace_old, workspace_new, C, CTX_data_active_object(C), &wm->reports);
#else
@@ -199,7 +202,7 @@ bool ED_workspace_change(
screen_changed_update(C, win, screen_new);
workspace_change_update(workspace_new, workspace_old, C, wm);
- BLI_assert(BKE_workspace_view_layer_get(workspace_new) != NULL);
+ BLI_assert(BKE_workspace_view_layer_get(workspace_new, CTX_data_scene(C)) != NULL);
BLI_assert(CTX_wm_workspace(C) == workspace_new);
WM_toolsystem_unlink(C, workspace_old);
@@ -220,15 +223,16 @@ WorkSpace *ED_workspace_duplicate(
{
WorkSpaceLayout *layout_active_old = BKE_workspace_active_layout_get(win->workspace_hook);
ListBase *layouts_old = BKE_workspace_layouts_get(workspace_old);
+ Scene *scene = WM_window_get_active_scene(win);
WorkSpace *workspace_new = ED_workspace_add(
- bmain, workspace_old->id.name + 2,
- BKE_workspace_view_layer_get(workspace_old),
+ bmain, workspace_old->id.name + 2, scene,
+ BKE_workspace_view_layer_get(workspace_old, scene),
&workspace_old->view_render);
ListBase *transform_orientations_old = BKE_workspace_transform_orientations_get(workspace_old);
ListBase *transform_orientations_new = BKE_workspace_transform_orientations_get(workspace_new);
#ifdef USE_WORKSPACE_MODE
- BKE_workspace_object_mode_set(workspace_new, BKE_workspace_object_mode_get(workspace_old));
+ BKE_workspace_object_mode_set(workspace_new, scene, BKE_workspace_object_mode_get(workspace_old, scene));
#endif
BLI_duplicatelist(transform_orientations_new, transform_orientations_old);
@@ -279,11 +283,12 @@ void ED_workspace_scene_data_sync(
}
void ED_workspace_view_layer_unset(
- const Main *bmain, const ViewLayer *layer_unset, ViewLayer *layer_new)
+ const Main *bmain, Scene *scene,
+ const ViewLayer *layer_unset, ViewLayer *layer_new)
{
for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
- if (BKE_workspace_view_layer_get(workspace) == layer_unset) {
- BKE_workspace_view_layer_set(workspace, layer_new);
+ if (BKE_workspace_view_layer_get(workspace, scene) == layer_unset) {
+ BKE_workspace_view_layer_set(workspace, layer_new, scene);
}
}
}
diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c
index 183d715a93e..8866c6b6c40 100644
--- a/source/blender/editors/space_buttons/buttons_context.c
+++ b/source/blender/editors/space_buttons/buttons_context.c
@@ -39,6 +39,7 @@
#include "BLT_translation.h"
#include "DNA_armature_types.h"
+#include "DNA_group_types.h"
#include "DNA_lamp_types.h"
#include "DNA_material_types.h"
#include "DNA_node_types.h"
@@ -177,7 +178,7 @@ static int buttons_context_path_workspace(ButsContextPath *path)
return RNA_struct_is_a(ptr->type, &RNA_WorkSpace);
}
-static int buttons_context_path_collection(ButsContextPath *path)
+static int buttons_context_path_collection(ButsContextPath *path, eSpaceButtons_Collection_Context collection_context)
{
PointerRNA *ptr = &path->ptr[path->len - 1];
@@ -187,10 +188,21 @@ static int buttons_context_path_collection(ButsContextPath *path)
}
ViewLayer *view_layer = ptr->data;
- LayerCollection *sc = BKE_layer_collection_get_active(view_layer);
- if (sc) {
- RNA_pointer_create(NULL, &RNA_LayerCollection, sc, &path->ptr[path->len]);
+ if (collection_context == SB_COLLECTION_CTX_GROUP) {
+ Object *ob = OBACT(view_layer);
+ if (ob && ob->dup_group) {
+ view_layer = ob->dup_group->view_layer;
+
+ /* Replace the view layer by the group in the context path. */
+ RNA_pointer_create(NULL, &RNA_Group, ob->dup_group, &path->ptr[path->len - 1]);
+ }
+ }
+
+ LayerCollection *layer_collection = BKE_layer_collection_get_active(view_layer);
+
+ if (layer_collection) {
+ RNA_pointer_create(NULL, &RNA_LayerCollection, layer_collection, &path->ptr[path->len]);
path->len++;
return 1;
}
@@ -650,7 +662,7 @@ static int buttons_context_path(const bContext *C, ButsContextPath *path, int ma
found = buttons_context_path_workspace(path);
break;
case BCONTEXT_COLLECTION:
- found = buttons_context_path_collection(path);
+ found = buttons_context_path_collection(path, sbuts->collection_context);
break;
case BCONTEXT_OBJECT:
case BCONTEXT_PHYSICS:
diff --git a/source/blender/editors/space_buttons/buttons_intern.h b/source/blender/editors/space_buttons/buttons_intern.h
index 7fc35a6b1e7..e6d19caad47 100644
--- a/source/blender/editors/space_buttons/buttons_intern.h
+++ b/source/blender/editors/space_buttons/buttons_intern.h
@@ -65,6 +65,7 @@ typedef struct ButsContextPath {
int len;
int flag;
int tex_ctx;
+ int collection_ctx;
} ButsContextPath;
typedef struct ButsTextureUser {
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index 74b20360a53..d2f407bfa8c 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -44,6 +44,7 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
#include "RNA_access.h"
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index cca33cdd1a7..217ce8f1d9a 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -151,15 +151,25 @@ static FileSelection file_selection_get(bContext *C, const rcti *rect, bool fill
/* if desired, fill the selection up from the last selected file to the current one */
if (fill && (sel.last >= 0) && (sel.last < numfiles) ) {
- int f = sel.last;
- while (f >= 0) {
+ int f;
+ /* Try to find a smaller-index selected item. */
+ for (f = sel.last; f >= 0; f--) {
if (filelist_entry_select_index_get(sfile->files, f, CHECK_ALL) )
break;
- f--;
}
if (f >= 0) {
sel.first = f + 1;
}
+ /* If none found, try to find a higher-index selected item. */
+ else {
+ for (f = sel.first; f < numfiles; f++) {
+ if (filelist_entry_select_index_get(sfile->files, f, CHECK_ALL) )
+ break;
+ }
+ if (f < numfiles) {
+ sel.last = f - 1;
+ }
+ }
}
return sel;
}
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index 780c2ec5a47..3f26604c23a 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -49,6 +49,7 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
#include "ED_space_api.h"
#include "ED_screen.h"
@@ -354,6 +355,33 @@ static void file_main_region_listener(
}
}
+static void file_main_region_message_subscribe(
+ const struct bContext *UNUSED(C),
+ struct WorkSpace *UNUSED(workspace), struct Scene *UNUSED(scene),
+ struct bScreen *screen, struct ScrArea *sa, struct ARegion *ar,
+ struct wmMsgBus *mbus)
+{
+ SpaceFile *sfile = sa->spacedata.first;
+ FileSelectParams *params = ED_fileselect_get_params(sfile);
+ /* This is a bit odd that a region owns the subscriber for an area,
+ * keep for now since all subscribers for WM are regions.
+ * May be worth re-visiting later. */
+ wmMsgSubscribeValue msg_sub_value_area_tag_refresh = {
+ .owner = ar,
+ .user_data = sa,
+ .notify = ED_area_do_msg_notify_tag_refresh,
+ };
+
+ /* FileSelectParams */
+ {
+ PointerRNA ptr;
+ RNA_pointer_create(&screen->id, &RNA_FileSelectParams, params, &ptr);
+
+ /* All properties for this space type. */
+ WM_msg_subscribe_rna(mbus, &ptr, NULL, &msg_sub_value_area_tag_refresh, __func__);
+ }
+}
+
static void file_main_region_draw(const bContext *C, ARegion *ar)
{
/* draw entirely, view changes should be handled here */
@@ -731,6 +759,7 @@ void ED_spacetype_file(void)
art->init = file_main_region_init;
art->draw = file_main_region_draw;
art->listener = file_main_region_listener;
+ art->message_subscribe = file_main_region_message_subscribe;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D;
BLI_addhead(&st->regiontypes, art);
diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c
index 53709e4cea7..3cf833756ef 100644
--- a/source/blender/editors/space_info/info_stats.c
+++ b/source/blender/editors/space_info/info_stats.c
@@ -270,6 +270,39 @@ static void stats_object_sculpt_dynamic_topology(Object *ob, SceneStats *stats)
stats->tottri = ob->sculpt->bm->totface;
}
+static void stats_dupli_object_group_count(SceneCollection *scene_collection, int *count)
+{
+ for (LinkData *link = scene_collection->objects.first; link; link = link->next) {
+ (*count)++;
+ }
+
+ SceneCollection *scene_collection_nested;
+ for (scene_collection_nested = scene_collection->scene_collections.first;
+ scene_collection_nested;
+ scene_collection_nested = scene_collection_nested->next)
+ {
+ stats_dupli_object_group_count(scene_collection_nested, count);
+ }
+}
+
+static void stats_dupli_object_group_doit(SceneCollection *scene_collection, SceneStats *stats, ParticleSystem *psys,
+ const int totgroup, int *cur)
+{
+ for (LinkData *link = scene_collection->objects.first; link; link = link->next) {
+ int tot = count_particles_mod(psys, totgroup, *cur);
+ stats_object(link->data, 0, tot, stats);
+ (*cur)++;
+ }
+
+ SceneCollection *scene_collection_nested;
+ for (scene_collection_nested = scene_collection->scene_collections.first;
+ scene_collection_nested;
+ scene_collection_nested = scene_collection_nested->next)
+ {
+ stats_dupli_object_group_doit(scene_collection_nested, stats, psys, totgroup, cur);
+ }
+}
+
static void stats_dupli_object(Base *base, Object *ob, SceneStats *stats)
{
if (base->flag & BASE_SELECTED) stats->totobjsel++;
@@ -287,17 +320,11 @@ static void stats_dupli_object(Base *base, Object *ob, SceneStats *stats)
stats_object(part->dup_ob, 0, tot, stats);
}
else if (part->draw_as == PART_DRAW_GR && part->dup_group) {
- GroupObject *go;
- int tot, totgroup = 0, cur = 0;
-
- for (go = part->dup_group->gobject.first; go; go = go->next)
- totgroup++;
-
- for (go = part->dup_group->gobject.first; go; go = go->next) {
- tot = count_particles_mod(psys, totgroup, cur);
- stats_object(go->ob, 0, tot, stats);
- cur++;
- }
+ int totgroup = 0, cur = 0;
+
+ SceneCollection *scene_collection = part->dup_group->collection;
+ stats_dupli_object_group_count(scene_collection, &totgroup);
+ stats_dupli_object_group_doit(scene_collection, stats, psys, totgroup, &cur);
}
}
diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c
index adf7e1dc5d3..d5c833a7b5f 100644
--- a/source/blender/editors/space_outliner/outliner_collections.c
+++ b/source/blender/editors/space_outliner/outliner_collections.c
@@ -36,6 +36,8 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
+#include "DNA_group_types.h"
+
#include "ED_screen.h"
#include "WM_api.h"
@@ -110,7 +112,7 @@ static int collection_link_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- SceneCollection *sc_master = BKE_collection_master(scene);
+ SceneCollection *sc_master = BKE_collection_master(&scene->id);
SceneCollection *sc;
int scene_collection_index = RNA_enum_get(op->ptr, "scene_collection");
@@ -136,7 +138,9 @@ static int collection_link_exec(bContext *C, wmOperator *op)
static int collection_link_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- if (BKE_collection_master(CTX_data_scene(C))->scene_collections.first == NULL) {
+ Scene *scene = CTX_data_scene(C);
+ SceneCollection *master_collection = BKE_collection_master(&scene->id);
+ if (master_collection->scene_collections.first == NULL) {
RNA_enum_set(op->ptr, "scene_collection", 0);
return collection_link_exec(C, op);
}
@@ -169,7 +173,7 @@ static const EnumPropertyItem *collection_scene_collection_itemf(
int value = 0, totitem = 0;
Scene *scene = CTX_data_scene(C);
- SceneCollection *sc = BKE_collection_master(scene);
+ SceneCollection *sc = BKE_collection_master(&scene->id);
collection_scene_collection_itemf_recursive(&tmp, &item, &totitem, &value, sc);
RNA_enum_item_end(&item, &totitem);
@@ -257,15 +261,18 @@ void OUTLINER_OT_collection_unlink(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/**********************************************************************************/
+/* Add new collection. */
+
static int collection_new_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
+ SceneCollection *scene_collection = BKE_collection_add(&scene->id, NULL, COLLECTION_TYPE_NONE, NULL);
+ BKE_collection_link(view_layer, scene_collection);
- SceneCollection *sc = BKE_collection_add(scene, NULL, NULL);
- BKE_collection_link(view_layer, sc);
-
- DEG_relations_tag_update(CTX_data_main(C));
+ DEG_relations_tag_update(bmain);
WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
return OPERATOR_FINISHED;
}
@@ -275,7 +282,7 @@ void OUTLINER_OT_collection_new(wmOperatorType *ot)
/* identifiers */
ot->name = "New Collection";
ot->idname = "OUTLINER_OT_collection_new";
- ot->description = "Add a new collection to the scene, and link it to the active layer";
+ ot->description = "Add a new collection to the scene";
/* api callbacks */
ot->exec = collection_new_exec;
@@ -284,6 +291,8 @@ void OUTLINER_OT_collection_new(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/**********************************************************************************/
+
/**
* Returns true is selected element is a collection
*/
@@ -325,9 +334,10 @@ void OUTLINER_OT_collection_override_new(wmOperatorType *ot)
struct CollectionDeleteData {
Scene *scene;
SpaceOops *soops;
+ GSet *collections_to_delete;
};
-static TreeTraversalAction collection_delete_cb(TreeElement *te, void *customdata)
+static TreeTraversalAction collection_find_data_to_delete(TreeElement *te, void *customdata)
{
struct CollectionDeleteData *data = customdata;
SceneCollection *scene_collection = outliner_scene_collection_from_tree_element(te);
@@ -336,12 +346,12 @@ static TreeTraversalAction collection_delete_cb(TreeElement *te, void *customdat
return TRAVERSE_SKIP_CHILDS;
}
- if (scene_collection == BKE_collection_master(data->scene)) {
+ if (scene_collection == BKE_collection_master(&data->scene->id)) {
/* skip - showing warning/error message might be missleading
* when deleting multiple collections, so just do nothing */
}
else {
- BKE_collection_remove(data->scene, scene_collection);
+ BLI_gset_add(data->collections_to_delete, scene_collection);
}
return TRAVERSE_CONTINUE;
@@ -353,8 +363,22 @@ static int collection_delete_exec(bContext *C, wmOperator *UNUSED(op))
SpaceOops *soops = CTX_wm_space_outliner(C);
struct CollectionDeleteData data = {.scene = scene, .soops = soops};
+ data.collections_to_delete = BLI_gset_ptr_new(__func__);
+
TODO_LAYER_OVERRIDE; /* handle overrides */
- outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_delete_cb, &data);
+
+ /* We first walk over and find the SceneCollections we actually want to delete (ignoring duplicates). */
+ outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_data_to_delete, &data);
+
+ /* Effectively delete the collections. */
+ GSetIterator collections_to_delete_iter;
+ GSET_ITER(collections_to_delete_iter, data.collections_to_delete) {
+
+ SceneCollection *sc = BLI_gsetIterator_getKey(&collections_to_delete_iter);
+ BKE_collection_remove(&data.scene->id, sc);
+ }
+
+ BLI_gset_free(data.collections_to_delete, NULL);
DEG_relations_tag_update(CTX_data_main(C));
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 8b4ed61f148..670fc4e6627 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -250,9 +250,16 @@ static void restrictbutton_gp_layer_flag_cb(bContext *C, void *UNUSED(poin), voi
static void enablebutton_collection_flag_cb(bContext *C, void *poin, void *poin2)
{
Main *bmain = CTX_data_main(C);
- Scene *scene = poin;
+ Scene *scene = CTX_data_scene(C);
+ ID *id = poin;
LayerCollection *layer_collection = poin2;
- ViewLayer *view_layer = BKE_view_layer_find_from_collection(scene, layer_collection);
+ ViewLayer *view_layer = BKE_view_layer_find_from_collection(id, layer_collection);
+
+ /* TODO: This breaks when you see the collections of a group. (dfelinto) */
+ if (view_layer == NULL) {
+ WM_reportf(RPT_INFO, "Enable/disable of group collections disabled for now");
+ return;
+ }
/* We need to toggle the flag since this is called after the flag is already set. */
layer_collection->flag ^= COLLECTION_DISABLED;
@@ -273,11 +280,16 @@ static void enablebutton_collection_flag_cb(bContext *C, void *poin, void *poin2
static void restrictbutton_collection_flag_cb(bContext *C, void *poin, void *UNUSED(poin2))
{
- Scene *scene = poin;
+ ID *id = (ID *)poin;
+
/* hide and deselect bases that are directly influenced by this LayerCollection */
/* TODO(sergey): Use proper flag for tagging here. */
- DEG_id_tag_update(&scene->id, 0);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ DEG_id_tag_update(id, 0);
+
+ if (GS(id->name) == ID_SCE) {
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, id);
+ }
+
WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, NULL);
}
@@ -595,22 +607,24 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_ENABLEX), te->ys, UI_UNIT_X,
UI_UNIT_Y, &collection->flag, 0, 0, 0, 0,
TIP_("Enable/Disable collection from depsgraph"));
- UI_but_func_set(bt, enablebutton_collection_flag_cb, scene, collection);
+ UI_but_func_set(bt, enablebutton_collection_flag_cb, tselem->id, collection);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE_N, COLLECTION_VISIBLE, 0, ICON_RESTRICT_VIEW_OFF,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X,
UI_UNIT_Y, &collection->flag, 0, 0, 0, 0,
TIP_("Restrict/Allow 3D View visibility of objects in the collection"));
- UI_but_func_set(bt, restrictbutton_collection_flag_cb, scene, collection);
+ UI_but_func_set(bt, restrictbutton_collection_flag_cb, tselem->id, collection);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
- bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE_N, COLLECTION_SELECTABLE, 0, ICON_RESTRICT_SELECT_OFF,
- (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X,
- UI_UNIT_Y, &collection->flag, 0, 0, 0, 0,
- TIP_("Restrict/Allow 3D View selection of objects in the collection"));
- UI_but_func_set(bt, restrictbutton_collection_flag_cb, scene, collection);
- UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
+ if (collection->scene_collection->type == COLLECTION_TYPE_NONE) {
+ bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE_N, COLLECTION_SELECTABLE, 0, ICON_RESTRICT_SELECT_OFF,
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X,
+ UI_UNIT_Y, &collection->flag, 0, 0, 0, 0,
+ TIP_("Restrict/Allow 3D View selection of objects in the collection"));
+ UI_but_func_set(bt, restrictbutton_collection_flag_cb, scene, collection);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
+ }
UI_block_emboss_set(block, UI_EMBOSS);
}
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 4858b6cb120..8cd76179f23 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -274,7 +274,7 @@ static void do_item_rename(const Scene *scene, ARegion *ar, TreeElement *te, Tre
BKE_report(reports, RPT_WARNING, "Cannot edit sequence name");
}
else if (ELEM(tselem->type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION)) {
- SceneCollection *master = BKE_collection_master(scene);
+ SceneCollection *master = BKE_collection_master(&scene->id);
if ((tselem->type == TSE_SCENE_COLLECTION && te->directdata == master) ||
(((LayerCollection *)te->directdata)->scene_collection == master))
@@ -1940,7 +1940,7 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
BLI_assert(scene);
RNA_string_get(op->ptr, "child", childname);
ob = (Object *)BKE_libblock_find_name(ID_OB, childname);
- BKE_collection_object_add(scene, sc, ob);
+ BKE_collection_object_add(&scene->id, sc, ob);
DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
@@ -2166,13 +2166,13 @@ static int scene_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
SceneCollection *sc;
if (scene != CTX_data_scene(C)) {
/* when linking to an inactive scene link to the master collection */
- sc = BKE_collection_master(scene);
+ sc = BKE_collection_master(&scene->id);
}
else {
sc = CTX_data_scene_collection(C);
}
- BKE_collection_object_add(scene, sc, ob);
+ BKE_collection_object_add(&scene->id, sc, ob);
for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
Base *base = BKE_view_layer_base_find(view_layer, ob);
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h
index 23e1b766891..f69eb9af1bf 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.h
@@ -67,9 +67,8 @@ typedef enum TreeTraversalAction {
/**
* Callback type for reinserting elements at a different position, used to allow user customizable element order.
- * Passing scene right now, may be better to allow some custom data.
*/
-typedef void (*TreeElementReinsertFunc)(struct Main *bmain, const struct Scene *scene,
+typedef void (*TreeElementReinsertFunc)(struct Main *bmain,
struct TreeElement *insert_element,
struct TreeElement *insert_handle, TreeElementInsertType action);
/**
@@ -77,7 +76,7 @@ typedef void (*TreeElementReinsertFunc)(struct Main *bmain, const struct Scene *
* if reinserting insert_element before/after/into insert_handle would be allowed.
* It's allowed to change the reinsert info here for non const pointers.
*/
-typedef bool (*TreeElementReinsertPollFunc)(const struct Scene *scene, const struct TreeElement *insert_element,
+typedef bool (*TreeElementReinsertPollFunc)(const struct TreeElement *insert_element,
struct TreeElement **io_insert_handle, TreeElementInsertType *io_action);
typedef TreeTraversalAction (*TreeTraversalFunc)(struct TreeElement *te, void *customdata);
diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c
index aa6a5dba6a7..856dd022c14 100644
--- a/source/blender/editors/space_outliner/outliner_ops.c
+++ b/source/blender/editors/space_outliner/outliner_ops.c
@@ -58,7 +58,7 @@ static int outliner_item_drag_drop_poll(bContext *C)
SpaceOops *soops = CTX_wm_space_outliner(C);
return ED_operator_outliner_active(C) &&
/* Only collection display modes supported for now. Others need more design work */
- ELEM(soops->outlinevis, SO_ACT_LAYER, SO_COLLECTIONS);
+ ELEM(soops->outlinevis, SO_ACT_LAYER, SO_COLLECTIONS, SO_GROUPS);
}
static TreeElement *outliner_item_drag_element_find(SpaceOops *soops, ARegion *ar, const wmEvent *event)
@@ -138,7 +138,7 @@ static void outliner_item_drag_get_insert_data(
}
static void outliner_item_drag_handle(
- const Scene *scene, SpaceOops *soops, ARegion *ar, const wmEvent *event, TreeElement *te_dragged)
+ SpaceOops *soops, ARegion *ar, const wmEvent *event, TreeElement *te_dragged)
{
TreeElement *te_insert_handle;
TreeElementInsertType insert_type;
@@ -156,7 +156,7 @@ static void outliner_item_drag_handle(
/* nothing will happen anyway, no need to do poll check */
}
else if (!te_dragged->reinsert_poll ||
- !te_dragged->reinsert_poll(scene, te_dragged, &te_insert_handle, &insert_type))
+ !te_dragged->reinsert_poll(te_dragged, &te_insert_handle, &insert_type))
{
te_insert_handle = NULL;
}
@@ -164,7 +164,7 @@ static void outliner_item_drag_handle(
te_dragged->drag_data->insert_handle = te_insert_handle;
}
-static bool outliner_item_drag_drop_apply(Main *bmain, const Scene *scene, TreeElement *dragged_te)
+static bool outliner_item_drag_drop_apply(Main *bmain, TreeElement *dragged_te)
{
TreeElement *insert_handle = dragged_te->drag_data->insert_handle;
TreeElementInsertType insert_type = dragged_te->drag_data->insert_type;
@@ -173,12 +173,12 @@ static bool outliner_item_drag_drop_apply(Main *bmain, const Scene *scene, TreeE
/* No need to do anything */
}
else if (dragged_te->reinsert) {
- BLI_assert(!dragged_te->reinsert_poll || dragged_te->reinsert_poll(scene, dragged_te, &insert_handle,
+ BLI_assert(!dragged_te->reinsert_poll || dragged_te->reinsert_poll(dragged_te, &insert_handle,
&insert_type));
/* call of assert above should not have changed insert_handle and insert_type at this point */
BLI_assert(dragged_te->drag_data->insert_handle == insert_handle &&
dragged_te->drag_data->insert_type == insert_type);
- dragged_te->reinsert(bmain, scene, dragged_te, insert_handle, insert_type);
+ dragged_te->reinsert(bmain, dragged_te, insert_handle, insert_type);
return true;
}
@@ -188,7 +188,6 @@ static bool outliner_item_drag_drop_apply(Main *bmain, const Scene *scene, TreeE
static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
TreeElement *te_dragged = op->customdata;
@@ -199,7 +198,7 @@ static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEv
switch (event->type) {
case EVT_MODAL_MAP:
if (event->val == OUTLINER_ITEM_DRAG_CONFIRM) {
- if (outliner_item_drag_drop_apply(bmain, scene, te_dragged)) {
+ if (outliner_item_drag_drop_apply(bmain, te_dragged)) {
skip_rebuild = false;
}
retval = OPERATOR_FINISHED;
@@ -215,7 +214,7 @@ static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEv
redraw = true;
break;
case MOUSEMOVE:
- outliner_item_drag_handle(scene, soops, ar, event, te_dragged);
+ outliner_item_drag_handle(soops, ar, event, te_dragged);
redraw = true;
break;
}
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index 5215efaa05c..08b5f337936 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -44,6 +44,7 @@
#include "BLI_listbase.h"
#include "BKE_context.h"
+#include "BKE_group.h"
#include "BKE_object.h"
#include "BKE_layer.h"
#include "BKE_scene.h"
@@ -780,12 +781,23 @@ static eOLDrawState tree_element_active_collection(
/* don't allow selecting a scene collection, it can have multiple layer collection
* instances (which one would the user want to be selected then?) */
else if (tselem->type == TSE_LAYER_COLLECTION) {
- ViewLayer *view_layer = CTX_data_view_layer(C);
- LayerCollection *lc = te->directdata;
- const int collection_index = BKE_layer_collection_findindex(view_layer, lc);
+ LayerCollection *layer_collection = te->directdata;
+
+ switch (layer_collection->scene_collection->type) {
+ case COLLECTION_TYPE_NONE:
+ case COLLECTION_TYPE_GROUP_INTERNAL:
+ {
+ ViewLayer *view_layer = BKE_view_layer_find_from_collection(tselem->id, layer_collection);
+ const int collection_index = BKE_layer_collection_findindex(view_layer, layer_collection);
- BLI_assert(collection_index >= 0);
- view_layer->active_collection = collection_index;
+ if (collection_index > -1) {
+ view_layer->active_collection = collection_index;
+ }
+ break;
+ }
+ default:
+ BLI_assert(!"Collection type not fully implemented");
+ }
WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
}
@@ -906,26 +918,30 @@ static void do_outliner_item_activate_tree_element(
}
else if (te->idcode == ID_GR) {
Group *gr = (Group *)tselem->id;
- GroupObject *gob;
if (extend) {
int sel = BA_SELECT;
- for (gob = gr->gobject.first; gob; gob = gob->next) {
- if (gob->ob->flag & SELECT) {
+ FOREACH_GROUP_BASE(gr, base)
+ {
+ if (base->flag & BASE_SELECTED) {
sel = BA_DESELECT;
break;
}
}
+ FOREACH_GROUP_BASE_END
- for (gob = gr->gobject.first; gob; gob = gob->next) {
- ED_object_base_select(BKE_view_layer_base_find(view_layer, gob->ob), sel);
+ FOREACH_GROUP_OBJECT(gr, object)
+ {
+ ED_object_base_select(BKE_view_layer_base_find(view_layer, object), sel);
}
+ FOREACH_GROUP_OBJECT_END
}
else {
BKE_view_layer_base_deselect_all(view_layer);
- for (gob = gr->gobject.first; gob; gob = gob->next) {
- Base *base = BKE_view_layer_base_find(view_layer, gob->ob);
+ FOREACH_GROUP_OBJECT(gr, object)
+ {
+ Base *base = BKE_view_layer_base_find(view_layer, object);
/* Object may not be in this scene */
if (base != NULL) {
if ((base->flag & BASE_SELECTED) == 0) {
@@ -933,6 +949,7 @@ static void do_outliner_item_activate_tree_element(
}
}
}
+ FOREACH_GROUP_OBJECT_END
}
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index 63e1a527138..99fd539293f 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -525,20 +525,21 @@ static void group_linkobs2scene_cb(
ViewLayer *view_layer = CTX_data_view_layer(C);
SceneCollection *sc = CTX_data_scene_collection(C);
Group *group = (Group *)tselem->id;
- GroupObject *gob;
Base *base;
- for (gob = group->gobject.first; gob; gob = gob->next) {
- base = BKE_view_layer_base_find(view_layer, gob->ob);
+ FOREACH_GROUP_OBJECT(group, object)
+ {
+ base = BKE_view_layer_base_find(view_layer, object);
if (!base) {
/* link to scene */
- BKE_collection_object_add(scene, sc, gob->ob);
- base = BKE_view_layer_base_find(view_layer, gob->ob);
- id_us_plus(&gob->ob->id);
+ BKE_collection_object_add(&scene->id, sc, object);
+ base = BKE_view_layer_base_find(view_layer, object);
+ id_us_plus(&object->id);
}
base->flag |= BASE_SELECTED;
}
+ FOREACH_GROUP_OBJECT_END
}
static void group_instance_cb(
@@ -663,6 +664,7 @@ typedef enum eOutliner_PropCollectionOps {
OL_COLLECTION_OP_COLLECTION_NEW,
OL_COLLECTION_OP_COLLECTION_DEL,
OL_COLLECTION_OP_COLLECTION_UNLINK,
+ OL_COLLECTION_OP_GROUP_CREATE,
} eOutliner_PropCollectionOps;
static void pchan_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg))
@@ -820,12 +822,13 @@ static void collection_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tsel
bContext *C = (bContext *)Carg;
Scene *scene = CTX_data_scene(C);
LayerCollection *lc = te->directdata;
+ ID *id = te->store_elem->id;
SceneCollection *sc = lc->scene_collection;
if (event == OL_COLLECTION_OP_OBJECTS_ADD) {
CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
{
- BKE_collection_object_add(scene, sc, ob);
+ BKE_collection_object_add(id, sc, ob);
}
CTX_DATA_END;
@@ -836,7 +839,7 @@ static void collection_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tsel
CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
{
- BKE_collection_object_remove(bmain, scene, sc, ob, true);
+ BKE_collection_object_remove(bmain, id, sc, ob, true);
}
CTX_DATA_END;
@@ -844,7 +847,13 @@ static void collection_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tsel
te->store_elem->flag &= ~TSE_SELECTED;
}
else if (event == OL_COLLECTION_OP_COLLECTION_NEW) {
- BKE_collection_add(scene, sc, NULL);
+ if (GS(id->name) == ID_GR) {
+ BKE_collection_add(id, sc, COLLECTION_TYPE_GROUP_INTERNAL, NULL);
+ }
+ else {
+ BLI_assert(GS(id->name) == ID_SCE);
+ BKE_collection_add(id, sc, COLLECTION_TYPE_NONE, NULL);
+ }
WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
}
else if (event == OL_COLLECTION_OP_COLLECTION_UNLINK) {
@@ -861,7 +870,7 @@ static void collection_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tsel
}
}
else if (event == OL_COLLECTION_OP_COLLECTION_DEL) {
- if (BKE_collection_remove(scene, sc)) {
+ if (BKE_collection_remove(id, sc)) {
DEG_relations_tag_update(CTX_data_main(C));
WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
}
@@ -870,6 +879,17 @@ static void collection_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tsel
TODO_LAYER_OPERATORS; /* this shouldn't be in the menu in those cases */
}
}
+ else if (event == OL_COLLECTION_OP_GROUP_CREATE) {
+ Main *bmain = CTX_data_main(C);
+ BKE_collection_group_create(bmain, scene, lc);
+ DEG_relations_tag_update(bmain);
+ /* TODO(sergey): Use proper flag for tagging here. */
+ DEG_id_tag_update(&scene->id, 0);
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
+ }
+ else {
+ BLI_assert(!"Collection operation not fully implemented!");
+ }
}
static void outliner_do_data_operation(SpaceOops *soops, int type, int event, ListBase *lb,
@@ -1794,15 +1814,39 @@ void OUTLINER_OT_modifier_operation(wmOperatorType *ot)
/* ******************** */
-static EnumPropertyItem prop_collection_op_types[] = {
- {OL_COLLECTION_OP_OBJECTS_ADD, "OBJECTS_ADD", ICON_ZOOMIN, "Add Selected", "Add selected objects to collection"},
- {OL_COLLECTION_OP_OBJECTS_REMOVE, "OBJECTS_REMOVE", ICON_X, "Remove Selected", "Remove selected objects from collection"},
- {OL_COLLECTION_OP_COLLECTION_NEW, "COLLECTION_NEW", ICON_NEW, "New Collection", "Add a new nested collection"},
- {OL_COLLECTION_OP_COLLECTION_UNLINK, "COLLECTION_UNLINK", ICON_UNLINKED, "Unlink", "Unlink collection"},
- {OL_COLLECTION_OP_COLLECTION_DEL, "COLLECTION_DEL", ICON_X, "Delete Collection", "Delete the collection"},
- {0, NULL, 0, NULL, NULL}
+static EnumPropertyItem prop_collection_op_none_types[] = {
+ {OL_COLLECTION_OP_OBJECTS_ADD, "OBJECTS_ADD", ICON_ZOOMIN, "Add Selected", "Add selected objects to collection"},
+ {OL_COLLECTION_OP_OBJECTS_REMOVE, "OBJECTS_REMOVE", ICON_X, "Remove Selected", "Remove selected objects from collection"},
+ {OL_COLLECTION_OP_COLLECTION_NEW, "COLLECTION_NEW", ICON_NEW, "New Collection", "Add a new nested collection"},
+ {OL_COLLECTION_OP_COLLECTION_UNLINK, "COLLECTION_UNLINK", ICON_UNLINKED, "Unlink", "Unlink collection"},
+ {OL_COLLECTION_OP_COLLECTION_DEL, "COLLECTION_DEL", ICON_X, "Delete Collection", "Delete the collection"},
+ {OL_COLLECTION_OP_GROUP_CREATE, "GROUP_CREATE", ICON_GROUP, "Create Group", "Turn the collection into a group collection"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static EnumPropertyItem prop_collection_op_group_internal_types[] = {
+ {OL_COLLECTION_OP_OBJECTS_ADD, "OBJECTS_ADD", ICON_ZOOMIN, "Add Selected", "Add selected objects to collection"},
+ {OL_COLLECTION_OP_OBJECTS_REMOVE, "OBJECTS_REMOVE", ICON_X, "Remove Selected", "Remove selected objects from collection"},
+ {OL_COLLECTION_OP_COLLECTION_NEW, "COLLECTION_NEW", ICON_NEW, "New Collection", "Add a new nested collection"},
+ {OL_COLLECTION_OP_COLLECTION_DEL, "COLLECTION_DEL", ICON_X, "Delete Collection", "Delete the collection"},
+ {0, NULL, 0, NULL, NULL}
};
+static const EnumPropertyItem *outliner_collection_operation_type_itemf(
+ bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ *r_free = false;
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+
+ switch (soops->outlinevis) {
+ case SO_GROUPS:
+ return prop_collection_op_group_internal_types;
+ case SO_ACT_LAYER:
+ return prop_collection_op_none_types;
+ }
+ return NULL;
+}
+
static int outliner_collection_operation_exec(bContext *C, wmOperator *op)
{
SpaceOops *soops = CTX_wm_space_outliner(C);
@@ -1823,6 +1867,8 @@ static int outliner_collection_operation_exec(bContext *C, wmOperator *op)
void OUTLINER_OT_collection_operation(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Outliner Collection Operation";
ot->idname = "OUTLINER_OT_collection_operation";
@@ -1835,7 +1881,10 @@ void OUTLINER_OT_collection_operation(wmOperatorType *ot)
ot->flag = 0;
- ot->prop = RNA_def_enum(ot->srna, "type", prop_collection_op_types, 0, "Collection Operation", "");
+ prop = RNA_def_enum(ot->srna, "type", DummyRNA_NULL_items, 0, "Collection Operation", "");
+ RNA_def_enum_funcs(prop, outliner_collection_operation_type_itemf);
+ RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
+ ot->prop = prop;
}
/* ******************** */
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index 1ab715d0246..a9c9ab74970 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -88,6 +88,8 @@
#endif
/* prototypes */
+static void outliner_add_layer_collections_recursive(
+ SpaceOops *soops, ListBase *tree, ID *id, ListBase *layer_collections, TreeElement *parent_ten);
static void outliner_make_hierarchy(ListBase *lb);
/* ********************************************************* */
@@ -386,13 +388,14 @@ static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *s
}
static void outliner_object_reorder(
- Main *UNUSED(bmain), const Scene *scene,
+ Main *UNUSED(bmain),
TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action)
{
TreeStoreElem *tselem_insert = TREESTORE(insert_element);
Object *ob = (Object *)tselem_insert->id;
SceneCollection *sc = outliner_scene_collection_from_tree_element(insert_handle);
SceneCollection *sc_ob_parent = NULL;
+ ID *id = insert_handle->store_elem->id;
BLI_assert(action == TE_INSERT_INTO);
UNUSED_VARS_NDEBUG(action);
@@ -407,13 +410,13 @@ static void outliner_object_reorder(
}
}
else {
- sc_ob_parent = BKE_collection_master(scene);
+ sc_ob_parent = BKE_collection_master(id);
}
- BKE_collection_object_move(scene, sc, sc_ob_parent, ob);
+ BKE_collection_object_move(id, sc, sc_ob_parent, ob);
}
static bool outliner_object_reorder_poll(
- const Scene *UNUSED(scene), const TreeElement *insert_element,
+ const TreeElement *insert_element,
TreeElement **io_insert_handle, TreeElementInsertType *io_action)
{
TreeStoreElem *tselem_handle = TREESTORE(*io_insert_handle);
@@ -861,7 +864,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
}
/* exceptions */
- if (ELEM(type, TSE_ID_BASE, TSE_LAYER_COLLECTION)) {
+ if (type == TSE_ID_BASE) {
/* pass */
}
else if (id == NULL) {
@@ -1199,6 +1202,11 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
te->flag |= TE_LAZY_CLOSED;
}
+ if ((type != TSE_LAYER_COLLECTION) && GS(id->name) == ID_GR) {
+ Group *group = (Group *)id;
+ outliner_add_layer_collections_recursive(soops, &te->subtree, id, &group->view_layer->layer_collections, NULL);
+ }
+
return te;
}
@@ -1349,20 +1357,21 @@ static void outliner_add_orphaned_datablocks(Main *mainvar, SpaceOops *soops)
}
static void outliner_layer_collections_reorder(
- Main *bmain, const Scene *scene,
+ Main *bmain,
TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action)
{
LayerCollection *lc_insert = insert_element->directdata;
LayerCollection *lc_handle = insert_handle->directdata;
+ ID *id = insert_element->store_elem->id;
if (action == TE_INSERT_BEFORE) {
- BKE_layer_collection_move_above(scene, lc_handle, lc_insert);
+ BKE_layer_collection_move_above(id, lc_handle, lc_insert);
}
else if (action == TE_INSERT_AFTER) {
- BKE_layer_collection_move_below(scene, lc_handle, lc_insert);
+ BKE_layer_collection_move_below(id, lc_handle, lc_insert);
}
else if (action == TE_INSERT_INTO) {
- BKE_layer_collection_move_into(scene, lc_handle, lc_insert);
+ BKE_layer_collection_move_into(id, lc_handle, lc_insert);
}
else {
BLI_assert(0);
@@ -1371,25 +1380,30 @@ static void outliner_layer_collections_reorder(
DEG_relations_tag_update(bmain);
}
static bool outliner_layer_collections_reorder_poll(
- const Scene *UNUSED(scene), const TreeElement *UNUSED(insert_element),
+ const TreeElement *insert_element,
TreeElement **io_insert_handle, TreeElementInsertType *UNUSED(io_action))
{
const TreeStoreElem *tselem_handle = TREESTORE(*io_insert_handle);
+
+ if (tselem_handle->id != insert_element->store_elem->id) {
+ return false;
+ }
+
return ELEM(tselem_handle->type, TSE_LAYER_COLLECTION);
}
static void outliner_add_layer_collections_recursive(
- SpaceOops *soops, ListBase *tree, ListBase *layer_collections, TreeElement *parent_ten)
+ SpaceOops *soops, ListBase *tree, ID *id, ListBase *layer_collections, TreeElement *parent_ten)
{
for (LayerCollection *collection = layer_collections->first; collection; collection = collection->next) {
- TreeElement *ten = outliner_add_element(soops, tree, collection, parent_ten, TSE_LAYER_COLLECTION, 0);
+ TreeElement *ten = outliner_add_element(soops, tree, id, parent_ten, TSE_LAYER_COLLECTION, 0);
ten->name = collection->scene_collection->name;
ten->directdata = collection;
ten->reinsert = outliner_layer_collections_reorder;
ten->reinsert_poll = outliner_layer_collections_reorder_poll;
- outliner_add_layer_collections_recursive(soops, &ten->subtree, &collection->layer_collections, ten);
+ outliner_add_layer_collections_recursive(soops, &ten->subtree, id, &collection->layer_collections, ten);
for (LinkData *link = collection->object_bases.first; link; link = link->next) {
Base *base = (Base *)link->data;
TreeElement *te_object = outliner_add_element(soops, &ten->subtree, base->object, ten, 0, 0);
@@ -1398,27 +1412,29 @@ static void outliner_add_layer_collections_recursive(
outliner_make_hierarchy(&ten->subtree);
}
}
-static void outliner_add_collections_act_layer(SpaceOops *soops, ViewLayer *layer)
+static void outliner_add_collections_act_layer(SpaceOops *soops, Scene *scene, ViewLayer *layer)
{
- outliner_add_layer_collections_recursive(soops, &soops->tree, &layer->layer_collections, NULL);
+ outliner_add_layer_collections_recursive(soops, &soops->tree, &scene->id, &layer->layer_collections, NULL);
}
static void outliner_scene_collections_reorder(
- Main *bmain, const Scene *scene,
+ Main *bmain,
TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action)
{
SceneCollection *sc_insert = insert_element->directdata;
SceneCollection *sc_handle = insert_handle->directdata;
+ ID *id = insert_handle->store_elem->id;
+ BLI_assert(id == insert_element->store_elem->id);
- BLI_assert((action == TE_INSERT_INTO) || (sc_handle != BKE_collection_master(scene)));
+ BLI_assert((action == TE_INSERT_INTO) || (sc_handle != BKE_collection_master(id)));
if (action == TE_INSERT_BEFORE) {
- BKE_collection_move_above(scene, sc_handle, sc_insert);
+ BKE_collection_move_above(id, sc_handle, sc_insert);
}
else if (action == TE_INSERT_AFTER) {
- BKE_collection_move_below(scene, sc_handle, sc_insert);
+ BKE_collection_move_below(id, sc_handle, sc_insert);
}
else if (action == TE_INSERT_INTO) {
- BKE_collection_move_into(scene, sc_handle, sc_insert);
+ BKE_collection_move_into(id, sc_handle, sc_insert);
}
else {
BLI_assert(0);
@@ -1427,17 +1443,23 @@ static void outliner_scene_collections_reorder(
DEG_relations_tag_update(bmain);
}
static bool outliner_scene_collections_reorder_poll(
- const Scene *scene, const TreeElement *UNUSED(insert_element),
+ const TreeElement *insert_element,
TreeElement **io_insert_handle, TreeElementInsertType *io_action)
{
const TreeStoreElem *tselem_handle = TREESTORE(*io_insert_handle);
- SceneCollection *sc_master = BKE_collection_master(scene);
- SceneCollection *sc_handle = (*io_insert_handle)->directdata;
+ ID *id = tselem_handle->id;
+
+ if (id != insert_element->store_elem->id) {
+ return false;
+ }
if (!ELEM(tselem_handle->type, TSE_SCENE_COLLECTION)) {
return false;
}
+ SceneCollection *sc_master = BKE_collection_master(id);
+ SceneCollection *sc_handle = (*io_insert_handle)->directdata;
+
if (sc_handle == sc_master) {
/* exception: Can't insert before/after master selection, has to be one of its childs */
TreeElement *te_master = *io_insert_handle;
@@ -1478,7 +1500,7 @@ static void outliner_add_scene_collections_recursive(
}
static void outliner_add_collections_master(SpaceOops *soops, Scene *scene)
{
- SceneCollection *master = BKE_collection_master(scene);
+ SceneCollection *master = BKE_collection_master(&scene->id);
outliner_add_scene_collections_recursive(soops, &soops->tree, &master->scene_collections, NULL);
outliner_add_scene_collection_objects(soops, &soops->tree, master, NULL);
}
@@ -1851,19 +1873,9 @@ void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, Spa
}
else if (soops->outlinevis == SO_GROUPS) {
Group *group;
- GroupObject *go;
-
for (group = mainvar->group.first; group; group = group->id.next) {
- if (group->gobject.first) {
- te = outliner_add_element(soops, &soops->tree, group, NULL, 0, 0);
-
- for (go = group->gobject.first; go; go = go->next) {
- outliner_add_element(soops, &te->subtree, go->ob, te, 0, 0);
- }
- outliner_make_hierarchy(&te->subtree);
- /* clear id.newid, to prevent objects be inserted in wrong scenes (parent in other scene) */
- for (go = group->gobject.first; go; go = go->next) go->ob->id.newid = NULL;
- }
+ te = outliner_add_element(soops, &soops->tree, group, NULL, 0, 0);
+ outliner_make_hierarchy(&te->subtree);
}
}
else if (soops->outlinevis == SO_SAME_TYPE) {
@@ -1940,7 +1952,7 @@ void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, Spa
outliner_add_orphaned_datablocks(mainvar, soops);
}
else if (soops->outlinevis == SO_ACT_LAYER) {
- outliner_add_collections_act_layer(soops, view_layer);
+ outliner_add_collections_act_layer(soops, scene, view_layer);
}
else if (soops->outlinevis == SO_COLLECTIONS) {
outliner_add_collections_master(soops, scene);
diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c
index ffaa259ab6f..1bc1a227a03 100644
--- a/source/blender/editors/space_outliner/space_outliner.c
+++ b/source/blender/editors/space_outliner/space_outliner.c
@@ -125,7 +125,8 @@ static int outliner_parent_drop_poll(bContext *C, wmDrag *drag, const wmEvent *e
*/
if (!scene) {
return 1;
- } else {
+ }
+ else {
for (ViewLayer *view_layer = scene->view_layers.first;
view_layer;
view_layer = view_layer->next)
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 399e76e71b8..04dbab0b853 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -157,6 +157,7 @@ void color3ubv_from_seq(Scene *curscene, Sequence *seq, unsigned char col[3])
case SEQ_TYPE_MULTICAM:
case SEQ_TYPE_ADJUSTMENT:
case SEQ_TYPE_GAUSSIAN_BLUR:
+ case SEQ_TYPE_COLORMIX:
UI_GetThemeColor3ubv(TH_SEQ_EFFECT, col);
/* slightly offset hue to distinguish different effects */
@@ -171,6 +172,7 @@ void color3ubv_from_seq(Scene *curscene, Sequence *seq, unsigned char col[3])
else if (seq->type == SEQ_TYPE_MULTICAM) rgb_byte_set_hue_float_offset(col, 0.32);
else if (seq->type == SEQ_TYPE_ADJUSTMENT) rgb_byte_set_hue_float_offset(col, 0.40);
else if (seq->type == SEQ_TYPE_GAUSSIAN_BLUR) rgb_byte_set_hue_float_offset(col, 0.42);
+ else if (seq->type == SEQ_TYPE_COLORMIX) rgb_byte_set_hue_float_offset(col, 0.46);
break;
case SEQ_TYPE_COLOR:
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index a8a5bc6e96b..8f6eb064b0d 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -95,6 +95,7 @@ EnumPropertyItem sequencer_prop_effect_types[] = {
{SEQ_TYPE_ADJUSTMENT, "ADJUSTMENT", 0, "Adjustment Layer", ""},
{SEQ_TYPE_GAUSSIAN_BLUR, "GAUSSIAN_BLUR", 0, "Gaussian Blur", ""},
{SEQ_TYPE_TEXT, "TEXT", 0, "Text", ""},
+ {SEQ_TYPE_COLORMIX, "COLORMIX", 0, "Color Mix", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -694,7 +695,7 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe)
BKE_sequence_calc(scene, seq);
}
- if ((seq->startstill) && (cutframe < seq->start)) {
+ if ((seq->startstill) && (cutframe <= seq->start)) {
/* don't do funny things with METAs ... */
if (seq->type == SEQ_TYPE_META) {
skip_dup = true;
@@ -708,13 +709,15 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe)
}
}
/* normal strip */
- else if ((cutframe >= seq->start) && (cutframe <= (seq->start + seq->len))) {
+ else if ((cutframe >= seq->start) && (cutframe < (seq->start + seq->len))) {
seq->endofs = 0;
seq->endstill = 0;
seq->anim_endofs += (seq->start + seq->len) - cutframe;
}
/* strips with extended stillframes after */
- else if (((seq->start + seq->len) < cutframe) && (seq->endstill)) {
+ else if (((seq->start + seq->len) == cutframe) ||
+ (((seq->start + seq->len) < cutframe) && (seq->endstill)))
+ {
seq->endstill -= seq->enddisp - cutframe;
/* don't do funny things with METAs ... */
if (seq->type == SEQ_TYPE_META) {
@@ -743,7 +746,7 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe)
}
/* normal strip */
- else if ((cutframe >= seqn->start) && (cutframe <= (seqn->start + seqn->len))) {
+ else if ((cutframe >= seqn->start) && (cutframe < (seqn->start + seqn->len))) {
seqn->start = cutframe;
seqn->startstill = 0;
seqn->startofs = 0;
@@ -754,7 +757,9 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe)
}
/* strips with extended stillframes after */
- else if (((seqn->start + seqn->len) < cutframe) && (seqn->endstill)) {
+ else if (((seqn->start + seqn->len) == cutframe) ||
+ (((seqn->start + seqn->len) < cutframe) && (seqn->endstill)))
+ {
seqn->start = cutframe;
seqn->startofs = 0;
seqn->anim_startofs += ts.len - 1;
@@ -790,7 +795,7 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe)
/* First Strip! */
/* strips with extended stillfames before */
- if ((seq->startstill) && (cutframe < seq->start)) {
+ if ((seq->startstill) && (cutframe <= seq->start)) {
/* don't do funny things with METAs ... */
if (seq->type == SEQ_TYPE_META) {
skip_dup = true;
@@ -804,11 +809,13 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe)
}
}
/* normal strip */
- else if ((cutframe >= seq->start) && (cutframe <= (seq->start + seq->len))) {
+ else if ((cutframe >= seq->start) && (cutframe < (seq->start + seq->len))) {
seq->endofs = (seq->start + seq->len) - cutframe;
}
/* strips with extended stillframes after */
- else if (((seq->start + seq->len) < cutframe) && (seq->endstill)) {
+ else if (((seq->start + seq->len) == cutframe) ||
+ (((seq->start + seq->len) < cutframe) && (seq->endstill)))
+ {
seq->endstill -= seq->enddisp - cutframe;
/* don't do funny things with METAs ... */
if (seq->type == SEQ_TYPE_META) {
@@ -834,9 +841,9 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe)
seqn->endofs = ts.endofs;
seqn->endstill = ts.endstill;
}
-
+
/* normal strip */
- else if ((cutframe >= seqn->start) && (cutframe <= (seqn->start + seqn->len))) {
+ if ((cutframe >= seqn->start) && (cutframe < (seqn->start + seqn->len))) {
seqn->startstill = 0;
seqn->startofs = cutframe - ts.start;
seqn->endofs = ts.endofs;
@@ -844,7 +851,9 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe)
}
/* strips with extended stillframes after */
- else if (((seqn->start + seqn->len) < cutframe) && (seqn->endstill)) {
+ else if (((seqn->start + seqn->len) == cutframe) ||
+ (((seqn->start + seqn->len) < cutframe) && (seqn->endstill)))
+ {
seqn->start = cutframe - ts.len + 1;
seqn->startofs = ts.len - 1;
seqn->endstill = ts.enddisp - cutframe - 1;
diff --git a/source/blender/editors/space_time/space_time.c b/source/blender/editors/space_time/space_time.c
index 99ac0d9024c..283dbf3b4e2 100644
--- a/source/blender/editors/space_time/space_time.c
+++ b/source/blender/editors/space_time/space_time.c
@@ -58,6 +58,9 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
+
+#include "RNA_access.h"
#include "BIF_gl.h"
@@ -649,6 +652,47 @@ static void time_main_region_listener(
}
}
+static void time_main_region_message_subscribe(
+ const struct bContext *UNUSED(C),
+ struct WorkSpace *UNUSED(workspace), struct Scene *scene,
+ struct bScreen *screen, struct ScrArea *sa, struct ARegion *ar,
+ struct wmMsgBus *mbus)
+{
+ PointerRNA ptr;
+ RNA_pointer_create(&screen->id, &RNA_SpaceTimeline, sa->spacedata.first, &ptr);
+
+ wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
+ .owner = ar,
+ .user_data = ar,
+ .notify = ED_region_do_msg_notify_tag_redraw,
+ };
+
+ /* Timeline depends on scene properties. */
+ {
+ bool use_preview = (scene->r.flag & SCER_PRV_RANGE);
+ extern PropertyRNA rna_Scene_frame_start;
+ extern PropertyRNA rna_Scene_frame_end;
+ extern PropertyRNA rna_Scene_frame_preview_start;
+ extern PropertyRNA rna_Scene_frame_preview_end;
+ extern PropertyRNA rna_Scene_use_preview_range;
+ extern PropertyRNA rna_Scene_frame_current;
+ const PropertyRNA *props[] = {
+ use_preview ? &rna_Scene_frame_preview_start : &rna_Scene_frame_start,
+ use_preview ? &rna_Scene_frame_preview_end : &rna_Scene_frame_end,
+ &rna_Scene_use_preview_range,
+ &rna_Scene_frame_current,
+ };
+
+ PointerRNA idptr;
+ RNA_id_pointer_create(&scene->id, &idptr);
+
+ for (int i = 0; i < ARRAY_SIZE(props); i++) {
+ WM_msg_subscribe_rna(mbus, &idptr, props[i], &msg_sub_value_region_tag_redraw, __func__);
+ }
+ }
+}
+
+
/* ************************ header time area region *********************** */
/* add handlers, stuff you only do once or on area/region changes */
@@ -797,6 +841,7 @@ void ED_spacetype_time(void)
art->init = time_main_region_init;
art->draw = time_main_region_draw;
art->listener = time_main_region_listener;
+ art->message_subscribe = time_main_region_message_subscribe;
art->keymap = time_keymap;
art->lock = 1; /* Due to pointcache, see T4960. */
BLI_addhead(&st->regiontypes, art);
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index 3e7e617bd0e..08ef9cc21cb 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -9458,6 +9458,8 @@ static void bbs_mesh_verts(BMEditMesh *em, DerivedMesh *dm, int offset)
#else
static void bbs_mesh_verts(BMEditMesh *em, DerivedMesh *UNUSED(dm), int offset)
{
+ glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
+
Mesh *me = em->ob->data;
Gwn_Batch *batch = DRW_mesh_batch_cache_get_verts_with_select_id(me, offset);
GWN_batch_program_set_builtin(batch, GPU_SHADER_3D_FLAT_COLOR_U32);
@@ -9497,7 +9499,7 @@ static void bbs_mesh_wire(BMEditMesh *em, DerivedMesh *dm, int offset)
immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR_U32);
- glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
+ glLineWidth(1.0f);
immBeginAtMost(GWN_PRIM_LINES, imm_len);
dm->foreachMappedEdge(dm, bbs_mesh_wire__mapFunc, &data);
@@ -9508,7 +9510,7 @@ static void bbs_mesh_wire(BMEditMesh *em, DerivedMesh *dm, int offset)
#else
static void bbs_mesh_wire(BMEditMesh *em, DerivedMesh *UNUSED(dm), int offset)
{
- glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
+ glLineWidth(1.0f);
Mesh *me = em->ob->data;
Gwn_Batch *batch = DRW_mesh_batch_cache_get_edges_with_select_id(me, offset);
@@ -9772,9 +9774,11 @@ void draw_object_backbufsel(
ED_view3d_polygon_offset(rv3d, 1.0);
- /* we draw edges always, for loop (select) tools */
- bbs_mesh_wire(em, dm, bm_solidoffs);
- bm_wireoffs = bm_solidoffs + em->bm->totedge;
+ /* we draw edges if edge select mode */
+ if (ts->selectmode & SCE_SELECT_EDGE) {
+ bbs_mesh_wire(em, dm, bm_solidoffs);
+ bm_wireoffs = bm_solidoffs + em->bm->totedge;
+ }
/* we draw verts if vert select mode. */
if (ts->selectmode & SCE_SELECT_VERTEX) {
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index f138b014d03..7cf1573de43 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -67,6 +67,7 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
#include "RE_engine.h"
#include "RE_pipeline.h"
@@ -1038,6 +1039,75 @@ static void view3d_main_region_listener(
}
}
+static void view3d_main_region_message_subscribe(
+ const struct bContext *UNUSED(C),
+ struct WorkSpace *workspace, struct Scene *scene,
+ struct bScreen *UNUSED(screen), struct ScrArea *UNUSED(sa), struct ARegion *ar,
+ struct wmMsgBus *mbus)
+{
+ /* Developer note: there are many properties that impact 3D view drawing,
+ * so instead of subscribing to individual properties, just subscribe to types
+ * accepting some redundant redraws.
+ *
+ * For other space types we might try avoid this, keep the 3D view as an exceptional case! */
+ ViewRender *view_render = BKE_viewrender_get(scene, workspace);
+ wmMsgParams_RNA msg_key_params = {0};
+
+ /* Only subscribe to types. */
+ StructRNA *type_array[] = {
+ /* These object have properties that impact drawing. */
+ &RNA_AreaLamp,
+ &RNA_Camera,
+ &RNA_Lamp,
+ &RNA_Speaker,
+ &RNA_SunLamp,
+
+ /* General types the 3D view depends on. */
+ &RNA_Object,
+ &RNA_UnitSettings, /* grid-floor */
+
+ &RNA_ViewRenderSettings,
+ &RNA_World,
+ };
+
+ wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
+ .owner = ar,
+ .user_data = ar,
+ .notify = ED_region_do_msg_notify_tag_redraw,
+ };
+
+ for (int i = 0; i < ARRAY_SIZE(type_array); i++) {
+ msg_key_params.ptr.type = type_array[i];
+ WM_msg_subscribe_rna_params(
+ mbus,
+ &msg_key_params,
+ &msg_sub_value_region_tag_redraw,
+ __func__);
+ }
+
+ /* Subscribe to a handful of other properties. */
+ RegionView3D *rv3d = ar->regiondata;
+
+ WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, resolution_x, &msg_sub_value_region_tag_redraw);
+ WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, resolution_y, &msg_sub_value_region_tag_redraw);
+ WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, pixel_aspect_x, &msg_sub_value_region_tag_redraw);
+ WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, pixel_aspect_y, &msg_sub_value_region_tag_redraw);
+ if (rv3d->persp == RV3D_CAMOB) {
+ WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, use_border, &msg_sub_value_region_tag_redraw);
+ }
+
+ /* Each engine could be responsible for its own engine data types.
+ * For now this is simplest. */
+ if (STREQ(view_render->engine_id, RE_engine_id_BLENDER_EEVEE)) {
+ extern StructRNA RNA_ViewLayerEngineSettingsEevee;
+ WM_msg_subscribe_rna_anon_type(mbus, ViewLayerEngineSettingsEevee, &msg_sub_value_region_tag_redraw);
+ }
+ else if (STREQ(view_render->engine_id, RE_engine_id_BLENDER_CLAY)) {
+ extern StructRNA RNA_ViewLayerEngineSettingsClay;
+ WM_msg_subscribe_rna_anon_type(mbus, ViewLayerEngineSettingsClay, &msg_sub_value_region_tag_redraw);
+ }
+}
+
/* concept is to retrieve cursor type context-less */
static void view3d_main_region_cursor(wmWindow *win, ScrArea *UNUSED(sa), ARegion *UNUSED(ar))
{
@@ -1379,6 +1449,7 @@ void ED_spacetype_view3d(void)
art->free = view3d_main_region_free;
art->duplicate = view3d_main_region_duplicate;
art->listener = view3d_main_region_listener;
+ art->message_subscribe = view3d_main_region_message_subscribe;
art->cursor = view3d_main_region_cursor;
art->lock = 1; /* can become flag, see BKE_spacedata_draw_locks */
BLI_addhead(&st->regiontypes, art);
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 8024a733f40..6ea2ff10af2 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -90,6 +90,8 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "RNA_access.h"
+
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -1931,8 +1933,8 @@ static void view3d_stereo3d_setup_offscreen(
void ED_view3d_draw_offscreen_init(const EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, View3D *v3d)
{
- RenderEngineType *type = eval_ctx->engine;
- if (type->flag & RE_USE_LEGACY_PIPELINE) {
+ RenderEngineType *engine_type = eval_ctx->engine_type;
+ if (engine_type->flag & RE_USE_LEGACY_PIPELINE) {
/* shadow buffers, before we setup matrices */
if (draw_glsl_material(scene, view_layer, NULL, v3d, v3d->drawtype)) {
VP_deprecated_gpu_update_lamps_shadows_world(eval_ctx, scene, v3d);
@@ -2014,8 +2016,8 @@ void ED_view3d_draw_offscreen(
view3d_main_region_setup_view(eval_ctx, scene, v3d, ar, viewmat, winmat, NULL);
/* main drawing call */
- RenderEngineType *type = eval_ctx->engine;
- if (type->flag & RE_USE_LEGACY_PIPELINE) {
+ RenderEngineType *engine_type = eval_ctx->engine_type;
+ if (engine_type->flag & RE_USE_LEGACY_PIPELINE) {
/* framebuffer fx needed, we need to draw offscreen first */
if (v3d->fx_settings.fx_flag && fx) {
@@ -2058,7 +2060,7 @@ void ED_view3d_draw_offscreen(
/* XXX, should take depsgraph as arg */
Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, false);
BLI_assert(depsgraph != NULL);
- DRW_draw_render_loop_offscreen(depsgraph, eval_ctx->engine, ar, v3d, ofs);
+ DRW_draw_render_loop_offscreen(depsgraph, eval_ctx->engine_type, ar, v3d, ofs);
}
/* restore size */
diff --git a/source/blender/editors/space_view3d/view3d_manipulator_camera.c b/source/blender/editors/space_view3d/view3d_manipulator_camera.c
index a4d408eedc6..d020571930a 100644
--- a/source/blender/editors/space_view3d/view3d_manipulator_camera.c
+++ b/source/blender/editors/space_view3d/view3d_manipulator_camera.c
@@ -45,6 +45,7 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
#include "view3d_intern.h" /* own include */
@@ -217,6 +218,55 @@ static void WIDGETGROUP_camera_refresh(const bContext *C, wmManipulatorGroup *mg
}
+static void WIDGETGROUP_camera_message_subscribe(
+ const bContext *C, wmManipulatorGroup *mgroup, struct wmMsgBus *mbus)
+{
+ ARegion *ar = CTX_wm_region(C);
+ Object *ob = CTX_data_active_object(C);
+ Camera *ca = ob->data;
+
+ wmMsgSubscribeValue msg_sub_value_mpr_tag_refresh = {
+ .owner = ar,
+ .user_data = mgroup->parent_mmap,
+ .notify = WM_manipulator_do_msg_notify_tag_refresh,
+ };
+
+ {
+ extern PropertyRNA rna_Camera_dof_distance;
+ extern PropertyRNA rna_Camera_draw_size;
+ extern PropertyRNA rna_Camera_ortho_scale;
+ extern PropertyRNA rna_Camera_sensor_fit;
+ extern PropertyRNA rna_Camera_sensor_width;
+ extern PropertyRNA rna_Camera_shift_x;
+ extern PropertyRNA rna_Camera_shift_y;
+ extern PropertyRNA rna_Camera_type;
+ const PropertyRNA *props[] = {
+ &rna_Camera_dof_distance,
+ &rna_Camera_draw_size,
+ &rna_Camera_ortho_scale,
+ &rna_Camera_sensor_fit,
+ &rna_Camera_sensor_width,
+ &rna_Camera_shift_x,
+ &rna_Camera_shift_y,
+ &rna_Camera_type,
+ };
+
+ PointerRNA idptr;
+ RNA_id_pointer_create(&ca->id, &idptr);
+
+ for (int i = 0; i < ARRAY_SIZE(props); i++) {
+ WM_msg_subscribe_rna(mbus, &idptr, props[i], &msg_sub_value_mpr_tag_refresh, __func__);
+ }
+ }
+
+ /* Subscribe to render settings */
+ {
+ WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, resolution_x, &msg_sub_value_mpr_tag_refresh);
+ WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, resolution_y, &msg_sub_value_mpr_tag_refresh);
+ WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, pixel_aspect_x, &msg_sub_value_mpr_tag_refresh);
+ WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, pixel_aspect_y, &msg_sub_value_mpr_tag_refresh);
+ }
+}
void VIEW3D_WGT_camera(wmManipulatorGroupType *wgt)
{
@@ -230,6 +280,7 @@ void VIEW3D_WGT_camera(wmManipulatorGroupType *wgt)
wgt->poll = WIDGETGROUP_camera_poll;
wgt->setup = WIDGETGROUP_camera_setup;
wgt->refresh = WIDGETGROUP_camera_refresh;
+ wgt->message_subscribe = WIDGETGROUP_camera_message_subscribe;
}
/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_manipulator_ruler.c b/source/blender/editors/space_view3d/view3d_manipulator_ruler.c
index 0495d1d696c..230b4f44c16 100644
--- a/source/blender/editors/space_view3d/view3d_manipulator_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_manipulator_ruler.c
@@ -272,7 +272,7 @@ static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state)
}
else if (state == RULER_STATE_DRAG) {
ruler_info->snap_context = ED_transform_snap_object_context_create_view3d(
- CTX_data_main(C), CTX_data_scene(C), CTX_data_view_layer(C), CTX_data_engine(C), 0,
+ CTX_data_main(C), CTX_data_scene(C), CTX_data_view_layer(C), CTX_data_engine_type(C), 0,
ruler_info->ar, CTX_wm_view3d(C));
}
else {
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index 568343f8ec8..79fa9e14dc1 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -46,6 +46,7 @@
#include "BKE_appdir.h"
#include "BKE_blender_copybuffer.h"
#include "BKE_context.h"
+#include "BKE_group.h"
#include "BKE_main.h"
#include "BKE_report.h"
@@ -81,14 +82,16 @@ static int view3d_copybuffer_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
for (Group *group = bmain->group.first; group; group = group->id.next) {
- for (GroupObject *go = group->gobject.first; go; go = go->next) {
- if (go->ob && (go->ob->id.tag & LIB_TAG_DOIT)) {
+ FOREACH_GROUP_OBJECT(group, object)
+ {
+ if (object && (object->id.tag & LIB_TAG_DOIT)) {
BKE_copybuffer_tag_ID(&group->id);
/* don't expand out to all other objects */
group->id.tag &= ~LIB_TAG_NEED_EXPAND;
break;
}
}
+ FOREACH_GROUP_OBJECT_END
}
BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer.blend");
diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c
index 5d213962ae9..093425fc3bc 100644
--- a/source/blender/editors/space_view3d/view3d_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_ruler.c
@@ -282,7 +282,7 @@ static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state)
}
else if (state == RULER_STATE_DRAG) {
ruler_info->snap_context = ED_transform_snap_object_context_create_view3d(
- CTX_data_main(C), CTX_data_scene(C), CTX_data_view_layer(C), CTX_data_engine(C), 0,
+ CTX_data_main(C), CTX_data_scene(C), CTX_data_view_layer(C), CTX_data_engine_type(C), 0,
ruler_info->ar, CTX_wm_view3d(C));
}
else {
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 4658ca566d2..28e15b3bfee 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -113,7 +113,7 @@ void view3d_set_viewcontext(bContext *C, ViewContext *vc)
vc->depsgraph = CTX_data_depsgraph(C);
vc->scene = CTX_data_scene(C);
vc->view_layer = CTX_data_view_layer(C);
- vc->engine = CTX_data_engine(C);
+ vc->engine_type = CTX_data_engine_type(C);
vc->v3d = CTX_wm_view3d(C);
vc->win = CTX_wm_window(C);
vc->rv3d = CTX_wm_region_view3d(C);
diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c
index 2901588b040..76da1faf530 100644
--- a/source/blender/editors/space_view3d/view3d_walk.c
+++ b/source/blender/editors/space_view3d/view3d_walk.c
@@ -251,7 +251,7 @@ typedef struct WalkInfo {
ARegion *ar;
Scene *scene;
ViewLayer *view_layer;
- RenderEngineType *engine;
+ RenderEngineType *engine_type;
wmTimer *timer; /* needed for redraws */
@@ -515,7 +515,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->ar = CTX_wm_region(C);
walk->scene = CTX_data_scene(C);
walk->view_layer = CTX_data_view_layer(C);
- walk->engine = CTX_data_engine(C);
+ walk->engine_type = CTX_data_engine_type(C);
#ifdef NDOF_WALK_DEBUG
puts("\n-- walk begin --");
@@ -604,7 +604,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->rv3d->rflag |= RV3D_NAVIGATING;
walk->snap_context = ED_transform_snap_object_context_create_view3d(
- CTX_data_main(C), walk->scene, walk->view_layer, walk->engine, 0,
+ CTX_data_main(C), walk->scene, walk->view_layer, walk->engine_type, 0,
walk->ar, walk->v3d);
walk->v3d_camera_control = ED_view3d_cameracontrol_acquire(
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index b6a9ba1079a..d9bfcd0c289 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -470,7 +470,7 @@ typedef struct TransInfo {
struct ARegion *ar;
struct Scene *scene;
struct ViewLayer *view_layer;
- struct RenderEngineType *engine;
+ struct RenderEngineType *engine_type;
struct ToolSettings *settings;
struct wmTimer *animtimer;
struct wmKeyMap *keymap; /* so we can do lookups for header text */
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index 89c43187bd4..730ca70547b 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -119,6 +119,7 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
#include "transform.h"
#include "bmesh.h"
@@ -1890,7 +1891,6 @@ static void createTransParticleVerts(bContext *C, TransInfo *t)
{
TransData *td = NULL;
TransDataExtension *tx;
- Base *base = CTX_data_active_base(C);
Object *ob = CTX_data_active_object(C);
ParticleEditSettings *pset = PE_settings(t->scene);
PTCacheEdit *edit = PE_get_current(t->scene, t->view_layer, ob);
@@ -1910,8 +1910,6 @@ static void createTransParticleVerts(bContext *C, TransInfo *t)
if (psys)
psmd = psys_get_modifier(ob, psys);
- base->flag |= BA_HAS_RECALC_DATA;
-
for (i = 0, point = edit->points; i < edit->totpoint; i++, point++) {
point->flag &= ~PEP_TRANSFORM;
transformparticle = 0;
@@ -2485,7 +2483,7 @@ static void createTransEditVerts(TransInfo *t)
int *island_vert_map = NULL;
DEG_evaluation_context_init_from_scene(&eval_ctx,
- t->scene, t->view_layer, t->engine,
+ t->scene, t->view_layer, t->engine_type,
DAG_EVAL_VIEWPORT);
/* Even for translation this is needed because of island-orientation, see: T51651. */
@@ -5531,6 +5529,37 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
}
}
+static void trans_object_base_deps_flag_prepare(ViewLayer *view_layer)
+{
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ base->object->id.tag &= ~LIB_TAG_DOIT;
+ }
+}
+
+static void set_trans_object_base_deps_flag_cb(ID *id, void *UNUSED(user_data))
+{
+ /* Here we only handle object IDs. */
+ if (GS(id->name) != ID_OB) {
+ return;
+ }
+ id->tag |= LIB_TAG_DOIT;
+}
+
+static void flush_trans_object_base_deps_flag(Depsgraph *depsgraph, Object *object)
+{
+ object->id.tag |= LIB_TAG_DOIT;
+ DEG_foreach_dependent_ID(depsgraph, &object->id,
+ set_trans_object_base_deps_flag_cb, NULL);
+}
+
+static void trans_object_base_deps_flag_finish(ViewLayer *view_layer)
+{
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (base->object->id.tag & LIB_TAG_DOIT) {
+ base->flag_legacy |= BA_SNAP_FIX_DEPS_FIASCO;
+ }
+ }
+}
/* sets flags in Bases to define whether they take part in transform */
/* it deselects Bases, so we have to call the clear function always after */
@@ -5541,47 +5570,30 @@ static void set_trans_object_base_flags(TransInfo *t)
ViewLayer *view_layer = t->view_layer;
Scene *scene = t->scene;
Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
-
- /*
- * if Base selected and has parent selected:
- * base->flag_legacy = BA_WAS_SEL
+ /* NOTE: if Base selected and has parent selected:
+ * base->flag_legacy = BA_WAS_SEL
*/
- Base *base;
-
- /* don't do it if we're not actually going to recalculate anything */
- if (t->mode == TFM_DUMMY)
+ /* Don't do it if we're not actually going to recalculate anything. */
+ if (t->mode == TFM_DUMMY) {
return;
-
- /* makes sure base flags and object flags are identical */
+ }
+ /* Makes sure base flags and object flags are identical. */
BKE_scene_base_flag_to_objects(t->view_layer);
-
/* Make sure depsgraph is here. */
DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
-
- /* handle pending update events, otherwise they got copied below */
- EvaluationContext eval_ctx;
- DEG_evaluation_context_init_from_scene(&eval_ctx,
- t->scene, t->view_layer, t->engine,
- DAG_EVAL_VIEWPORT);
- for (base = view_layer->object_bases.first; base; base = base->next) {
- if (base->object->recalc & OB_RECALC_ALL) {
- /* TODO(sergey): Ideally, it's not needed. */
- BKE_object_handle_update(&eval_ctx, t->scene, base->object);
- }
- }
-
- for (base = view_layer->object_bases.first; base; base = base->next) {
+ /* Clear all flags we need. It will be used to detect dependencies. */
+ trans_object_base_deps_flag_prepare(view_layer);
+ /* Traverse all bases and set all possible flags. */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
base->flag_legacy &= ~BA_WAS_SEL;
-
if (TESTBASELIB_BGMODE(base)) {
Object *ob = base->object;
Object *parsel = ob->parent;
-
- /* if parent selected, deselect */
- while (parsel) {
+ /* If parent selected, deselect. */
+ while (parsel != NULL) {
if (parsel->base_flag & BASE_SELECTED) {
Base *parbase = BKE_view_layer_base_find(view_layer, parsel);
- if (parbase) { /* in rare cases this can fail */
+ if (parbase != NULL) { /* in rare cases this can fail */
if (TESTBASELIB_BGMODE(parbase)) {
break;
}
@@ -5589,9 +5601,8 @@ static void set_trans_object_base_flags(TransInfo *t)
}
parsel = parsel->parent;
}
-
- if (parsel) {
- /* rotation around local centers are allowed to propagate */
+ if (parsel != NULL) {
+ /* Rotation around local centers are allowed to propagate. */
if ((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
(t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL))
{
@@ -5602,21 +5613,13 @@ static void set_trans_object_base_flags(TransInfo *t)
base->flag_legacy |= BA_WAS_SEL;
}
}
- DEG_id_tag_update(&ob->id, OB_RECALC_OB);
+ flush_trans_object_base_deps_flag(depsgraph, ob);
}
}
-
- /* all recalc flags get flushed to all layers, so a layer flip later on works fine */
- DEG_graph_flush_update(bmain, depsgraph);
-
- /* and we store them temporal in base (only used for transform code) */
- /* this because after doing updates, the object->recalc is cleared */
- for (base = view_layer->object_bases.first; base; base = base->next) {
- if (base->object->recalc & OB_RECALC_OB)
- base->flag_legacy |= BA_HAS_RECALC_OB;
- if (base->object->recalc & OB_RECALC_DATA)
- base->flag_legacy |= BA_HAS_RECALC_DATA;
- }
+ /* Store temporary bits in base indicating that base is being modified
+ * (directly or indirectly) by transforming objects.
+ */
+ trans_object_base_deps_flag_finish(view_layer);
}
static bool mark_children(Object *ob)
@@ -5637,32 +5640,28 @@ static bool mark_children(Object *ob)
static int count_proportional_objects(TransInfo *t)
{
int total = 0;
- /* TODO(sergey): Get rid of global, use explicit main. */
- Main *bmain = G.main;
ViewLayer *view_layer = t->view_layer;
Scene *scene = t->scene;
Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
- Base *base;
-
- /* rotations around local centers are allowed to propagate, so we take all objects */
+ /* Clear all flags we need. It will be used to detect dependencies. */
+ trans_object_base_deps_flag_prepare(view_layer);
+ /* Rotations around local centers are allowed to propagate, so we take all objects. */
if (!((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
(t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL)))
{
- /* mark all parents */
- for (base = view_layer->object_bases.first; base; base = base->next) {
+ /* Mark all parents. */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
if (TESTBASELIB_BGMODE(base)) {
Object *parent = base->object->parent;
-
/* flag all parents */
- while (parent) {
+ while (parent != NULL) {
parent->flag |= BA_TRANSFORM_PARENT;
parent = parent->parent;
}
}
}
-
- /* mark all children */
- for (base = view_layer->object_bases.first; base; base = base->next) {
+ /* Mark all children. */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
/* all base not already selected or marked that is editable */
if ((base->object->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
(base->flag & BASE_SELECTED) == 0 &&
@@ -5672,36 +5671,24 @@ static int count_proportional_objects(TransInfo *t)
}
}
}
-
- for (base = view_layer->object_bases.first; base; base = base->next) {
+ /* Flush changed flags to all dependencies. */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
Object *ob = base->object;
-
- /* if base is not selected, not a parent of selection or not a child of selection and it is editable */
+ /* If base is not selected, not a parent of selection or not a child of
+ * selection and it is editable.
+ */
if ((ob->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
(base->flag & BASE_SELECTED) == 0 &&
(BASE_EDITABLE_BGMODE(base)))
{
-
- DEG_id_tag_update(&ob->id, OB_RECALC_OB);
-
+ flush_trans_object_base_deps_flag(depsgraph, ob);
total += 1;
}
}
-
-
- /* all recalc flags get flushed to all layers, so a layer flip later on works fine */
- DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
- DEG_graph_flush_update(bmain, depsgraph);
-
- /* and we store them temporal in base (only used for transform code) */
- /* this because after doing updates, the object->recalc is cleared */
- for (base = view_layer->object_bases.first; base; base = base->next) {
- if (base->object->recalc & OB_RECALC_OB)
- base->flag_legacy |= BA_HAS_RECALC_OB;
- if (base->object->recalc & OB_RECALC_DATA)
- base->flag_legacy |= BA_HAS_RECALC_DATA;
- }
-
+ /* Store temporary bits in base indicating that base is being modified
+ * (directly or indirectly) by transforming objects.
+ */
+ trans_object_base_deps_flag_finish(view_layer);
return total;
}
@@ -5715,7 +5702,7 @@ static void clear_trans_object_base_flags(TransInfo *t)
base->flag |= BASE_SELECTED;
}
- base->flag_legacy &= ~(BA_WAS_SEL | BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA | BA_TEMP_TAG | BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT);
+ base->flag_legacy &= ~(BA_WAS_SEL | BA_SNAP_FIX_DEPS_FIASCO | BA_TEMP_TAG | BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT);
}
}
@@ -6489,12 +6476,16 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
else if (arm->flag & ARM_DELAYDEFORM) {
- /* old optimize trick... this enforces to bypass the depgraph */
+ /* TODO(sergey): Armature is already updated by recalcData(), so we
+ * might save some time by skipping re-evaluating it. But this isn't
+ * possible yet within new dependency graph, and also other contexts
+ * might need to update their CoW copies.
+ */
DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
- ob->recalc = 0; // is set on OK position already by recalcData()
}
- else
+ else {
DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
}
else if (t->options & CTX_PAINT_CURVE) {
@@ -8291,7 +8282,7 @@ void createTransData(bContext *C, TransInfo *t)
RegionView3D *rv3d = t->ar->regiondata;
if ((rv3d->persp == RV3D_CAMOB) && v3d->camera) {
/* we could have a flag to easily check an object is being transformed */
- if (v3d->camera->recalc) {
+ if (v3d->camera->id.tag & LIB_TAG_DOIT) {
t->flag |= T_CAMERA;
}
}
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index f6ec93d8ff9..10a7677f42b 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -1123,12 +1123,12 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
Object *obedit = CTX_data_edit_object(C);
Object *ob = CTX_data_active_object(C);
bGPdata *gpd = CTX_data_gpencil_data(C);
- RenderEngineType *engine = CTX_data_engine(C);
+ RenderEngineType *engine_type = CTX_data_engine_type(C);
PropertyRNA *prop;
t->scene = sce;
t->view_layer = view_layer;
- t->engine = engine;
+ t->engine_type = engine_type;
t->sa = sa;
t->ar = ar;
t->obedit = obedit;
diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c
index ee722397f91..0e0c2f3ae25 100644
--- a/source/blender/editors/transform/transform_manipulator.c
+++ b/source/blender/editors/transform/transform_manipulator.c
@@ -65,6 +65,7 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
#include "ED_armature.h"
#include "ED_curve.h"
@@ -1115,6 +1116,47 @@ static void manipulator_line_range(const View3D *v3d, const short axis_type, flo
*r_len -= *r_start;
}
+static void manipulator_xform_message_subscribe(
+ wmManipulatorGroup *mgroup, struct wmMsgBus *mbus,
+ bScreen *screen, ScrArea *sa, ARegion *ar, const void *type_fn)
+{
+ /* Subscribe to view properties */
+ wmMsgSubscribeValue msg_sub_value_mpr_tag_refresh = {
+ .owner = ar,
+ .user_data = mgroup->parent_mmap,
+ .notify = WM_manipulator_do_msg_notify_tag_refresh,
+ };
+
+ PointerRNA space_ptr;
+ RNA_pointer_create(&screen->id, &RNA_SpaceView3D, sa->spacedata.first, &space_ptr);
+
+ {
+ extern PropertyRNA rna_SpaceView3D_transform_orientation;
+ const PropertyRNA *props[] = {
+ &rna_SpaceView3D_transform_orientation,
+ };
+ for (int i = 0; i < ARRAY_SIZE(props); i++) {
+ WM_msg_subscribe_rna(mbus, &space_ptr, props[i], &msg_sub_value_mpr_tag_refresh, __func__);
+ }
+ }
+
+ if (type_fn == TRANSFORM_WGT_manipulator) {
+ extern PropertyRNA rna_SpaceView3D_pivot_point;
+ const PropertyRNA *props[] = {
+ &rna_SpaceView3D_pivot_point
+ };
+ for (int i = 0; i < ARRAY_SIZE(props); i++) {
+ WM_msg_subscribe_rna(mbus, &space_ptr, props[i], &msg_sub_value_mpr_tag_refresh, __func__);
+ }
+ }
+ else if (type_fn == VIEW3D_WGT_xform_cage) {
+ /* pass */
+ }
+ else {
+ BLI_assert(0);
+ }
+}
+
/** \} */
@@ -1383,6 +1425,15 @@ static void WIDGETGROUP_manipulator_refresh(const bContext *C, wmManipulatorGrou
MAN_ITER_AXES_END;
}
+static void WIDGETGROUP_manipulator_message_subscribe(
+ const bContext *C, wmManipulatorGroup *mgroup, struct wmMsgBus *mbus)
+{
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+ manipulator_xform_message_subscribe(mgroup, mbus, screen, sa, ar, TRANSFORM_WGT_manipulator);
+}
+
static void WIDGETGROUP_manipulator_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup)
{
ManipulatorGroup *man = mgroup->customdata;
@@ -1464,6 +1515,7 @@ void TRANSFORM_WGT_manipulator(wmManipulatorGroupType *wgt)
wgt->poll = WIDGETGROUP_manipulator_poll;
wgt->setup = WIDGETGROUP_manipulator_setup;
wgt->refresh = WIDGETGROUP_manipulator_refresh;
+ wgt->message_subscribe = WIDGETGROUP_manipulator_message_subscribe;
wgt->draw_prepare = WIDGETGROUP_manipulator_draw_prepare;
}
@@ -1500,7 +1552,7 @@ static void WIDGETGROUP_xform_cage_setup(const bContext *UNUSED(C), wmManipulato
ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE);
mpr->color[0] = 1;
- mpr->color_hi[0]=1;
+ mpr->color_hi[0] =1;
mgroup->customdata = xmgroup;
@@ -1585,6 +1637,15 @@ static void WIDGETGROUP_xform_cage_refresh(const bContext *C, wmManipulatorGroup
}
}
+static void WIDGETGROUP_xform_cage_message_subscribe(
+ const bContext *C, wmManipulatorGroup *mgroup, struct wmMsgBus *mbus)
+{
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+ manipulator_xform_message_subscribe(mgroup, mbus, screen, sa, ar, VIEW3D_WGT_xform_cage);
+}
+
static void WIDGETGROUP_xform_cage_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup)
{
struct XFormCageWidgetGroup *xmgroup = mgroup->customdata;
@@ -1613,6 +1674,7 @@ void VIEW3D_WGT_xform_cage(wmManipulatorGroupType *wgt)
wgt->poll = WIDGETGROUP_xform_cage_poll;
wgt->setup = WIDGETGROUP_xform_cage_setup;
wgt->refresh = WIDGETGROUP_xform_cage_refresh;
+ wgt->message_subscribe = WIDGETGROUP_xform_cage_message_subscribe;
wgt->draw_prepare = WIDGETGROUP_xform_cage_draw_prepare;
}
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 6b3167a0392..30aad46843d 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -300,9 +300,7 @@ void applyProject(TransInfo *t)
mul_m4_v3(ob->obmat, iloc);
}
else if (t->flag & T_OBJECT) {
- /* TODO(sergey): Ideally force update is not needed here. */
- td->ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME;
- BKE_object_handle_update(G.main->eval_ctx, t->scene, td->ob);
+ BKE_object_eval_transform_all(G.main->eval_ctx, t->scene, td->ob);
copy_v3_v3(iloc, td->ob->obmat[3]);
}
@@ -391,8 +389,7 @@ void applyGridAbsolute(TransInfo *t)
mul_m4_v3(obmat, iloc);
}
else if (t->flag & T_OBJECT) {
- td->ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME;
- BKE_object_handle_update(G.main->eval_ctx, t->scene, td->ob);
+ BKE_object_eval_transform_all(G.main->eval_ctx, t->scene, td->ob);
copy_v3_v3(iloc, td->ob->obmat[3]);
}
@@ -585,7 +582,7 @@ static void initSnappingMode(TransInfo *t)
if (t->spacetype == SPACE_VIEW3D) {
if (t->tsnap.object_context == NULL) {
t->tsnap.object_context = ED_transform_snap_object_context_create_view3d(
- G.main, t->scene, t->view_layer, t->engine, 0,
+ G.main, t->scene, t->view_layer, t->engine_type, 0,
t->ar, t->view);
ED_transform_snap_object_context_set_editmesh_callbacks(
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index 61705ba2868..ce8de2ef4d3 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -161,17 +161,8 @@ static void iter_snap_objects(
void *data)
{
Base *base_act = sctx->eval_ctx.view_layer->basact;
- /* Need an exception for particle edit because the base is flagged with BA_HAS_RECALC_DATA
- * which makes the loop skip it, even the derived mesh will never change
- *
- * To solve that problem, we do it first as an exception.
- * */
- if (base_act && base_act->object && base_act->object->mode & OB_MODE_PARTICLE_EDIT) {
- sob_callback(sctx, false, base_act->object, base_act->object->obmat, data);
- }
-
for (Base *base = sctx->eval_ctx.view_layer->object_bases.first; base != NULL; base = base->next) {
- if ((BASE_VISIBLE(base)) && (base->flag_legacy & (BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA)) == 0 &&
+ if ((BASE_VISIBLE(base)) && (base->flag_legacy & BA_SNAP_FIX_DEPS_FIASCO) == 0 &&
!((snap_select == SNAP_NOT_SELECTED && ((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL))) ||
(snap_select == SNAP_NOT_ACTIVE && base == base_act)))
{
@@ -2096,7 +2087,7 @@ static bool snapObjectsRay(
* \{ */
SnapObjectContext *ED_transform_snap_object_context_create(
- Main *bmain, Scene *scene, ViewLayer *view_layer, RenderEngineType *engine, int flag)
+ Main *bmain, Scene *scene, ViewLayer *view_layer, RenderEngineType *engine_type, int flag)
{
SnapObjectContext *sctx = MEM_callocN(sizeof(*sctx), __func__);
@@ -2105,7 +2096,7 @@ SnapObjectContext *ED_transform_snap_object_context_create(
sctx->bmain = bmain;
sctx->scene = scene;
- DEG_evaluation_context_init_from_scene(&sctx->eval_ctx, scene, view_layer, engine, DAG_EVAL_VIEWPORT);
+ DEG_evaluation_context_init_from_scene(&sctx->eval_ctx, scene, view_layer, engine_type, DAG_EVAL_VIEWPORT);
sctx->cache.object_map = BLI_ghash_ptr_new(__func__);
sctx->cache.mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
@@ -2114,11 +2105,11 @@ SnapObjectContext *ED_transform_snap_object_context_create(
}
SnapObjectContext *ED_transform_snap_object_context_create_view3d(
- Main *bmain, Scene *scene, ViewLayer *view_layer, RenderEngineType *engine, int flag,
+ Main *bmain, Scene *scene, ViewLayer *view_layer, RenderEngineType *engine_type, int flag,
/* extra args for view3d */
const ARegion *ar, const View3D *v3d)
{
- SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, view_layer, engine, flag);
+ SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, view_layer, engine_type, flag);
sctx->use_v3d = true;
sctx->v3d_data.ar = ar;
diff --git a/source/blender/editors/util/numinput.c b/source/blender/editors/util/numinput.c
index 61142fdc887..0f3240946fd 100644
--- a/source/blender/editors/util/numinput.c
+++ b/source/blender/editors/util/numinput.c
@@ -488,8 +488,9 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
const float fac = (float)BKE_scene_unit_scale(&sce->unit, n->unit_type[idx], 1.0);
/* Make radian default unit when needed. */
- if (n->unit_use_radians && n->unit_type[idx] == B_UNIT_ROTATION)
+ if (n->unit_use_radians && n->unit_type[idx] == B_UNIT_ROTATION) {
default_unit = "r";
+ }
BLI_strncpy(str_unit_convert, n->str, sizeof(str_unit_convert));
@@ -513,7 +514,16 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
n->val[idx] = -n->val[idx];
}
if (n->val_flag[idx] & NUM_INVERSE) {
- n->val[idx] = 1.0f / n->val[idx];
+ val = n->val[idx];
+ /* If we invert on radians when user is in degrees, you get unexpected results... See T53463. */
+ if (!n->unit_use_radians && n->unit_type[idx] == B_UNIT_ROTATION) {
+ val = RAD2DEG(val);
+ }
+ val = 1.0 / val;
+ if (!n->unit_use_radians && n->unit_type[idx] == B_UNIT_ROTATION) {
+ val = DEG2RAD(val);
+ }
+ n->val[idx] = (float)val;
}
if (UNLIKELY(!isfinite(n->val[idx]))) {
diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c
index c24e4994f7f..dbf1cf46c61 100644
--- a/source/blender/editors/util/undo.c
+++ b/source/blender/editors/util/undo.c
@@ -45,6 +45,7 @@
#include "BKE_blender_undo.h"
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_library_override.h"
#include "BKE_main.h"
#include "BKE_screen.h"
@@ -82,6 +83,9 @@ void ED_undo_push(bContext *C, const char *str)
if (G.debug & G_DEBUG)
printf("%s: %s\n", __func__, str);
+ /* Always do it for now, this might need to be refined... */
+ BKE_main_override_static_operations_create(CTX_data_main(C));
+
if (obedit) {
if (U.undosteps == 0) return;
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
index 6122ef99964..79f17756ca6 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
@@ -945,8 +945,8 @@ Object *BlenderStrokeRenderer::NewMesh() const
ob->data = BKE_mesh_add(freestyle_bmain, name);
ob->lay = 1;
- SceneCollection *sc_master = BKE_collection_master(freestyle_scene);
- BKE_collection_object_add(freestyle_scene, sc_master, ob);
+ SceneCollection *sc_master = BKE_collection_master(&freestyle_scene->id);
+ BKE_collection_object_add(&freestyle_scene->id, sc_master, ob);
DEG_graph_tag_relations_update(freestyle_depsgraph);
DEG_graph_id_tag_update(freestyle_bmain,
diff --git a/source/blender/freestyle/intern/system/PythonInterpreter.h b/source/blender/freestyle/intern/system/PythonInterpreter.h
index 0e08af1bac8..79ba9421cda 100644
--- a/source/blender/freestyle/intern/system/PythonInterpreter.h
+++ b/source/blender/freestyle/intern/system/PythonInterpreter.h
@@ -52,7 +52,7 @@ extern "C" {
#include "BPY_extern.h"
-#include "bpy_util.h"
+#include "bpy_capi_utils.h"
}
namespace Freestyle {
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index bc91df895c8..9e4daa2a036 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -1589,6 +1589,15 @@ static GPUNodeLink *gpu_uniformbuffer_link(
GPUMaterial *mat, bNode *node, GPUNodeStack *stack, const int index, const eNodeSocketInOut in_out)
{
bNodeSocket *socket;
+
+ /* Some nodes can have been create on the fly and does
+ * not have an original to point to. (i.e. the bump from
+ * ntree_shader_relink_displacement). In this case just
+ * revert to static constant folding. */
+ if (node->original == NULL) {
+ return NULL;
+ }
+
if (in_out == SOCK_IN) {
socket = BLI_findlink(&node->original->inputs, index);
}
diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c
index 231f1d8f7b1..57df877bf18 100644
--- a/source/blender/gpu/intern/gpu_extensions.c
+++ b/source/blender/gpu/intern/gpu_extensions.c
@@ -181,7 +181,8 @@ void gpu_extensions_init(void)
/* XXX : TODO : Remove this once this sampling mipmap problem is gone.
* https://github.com/dfelinto/opengl-sandbox/blob/downsample/README.md */
else if (strstr(renderer, "AMD VEGA") &&
- strstr(vendor, "X.Org")) {
+ strstr(vendor, "X.Org"))
+ {
GG.device = GPU_DEVICE_AMD_VEGA;
GG.driver = GPU_DRIVER_OPENSOURCE;
}
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index 0a8ef9dffc5..e2883b53047 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -516,9 +516,9 @@ static float gaussian_profile(float r, float radius)
const float v = radius * radius * (0.25f * 0.25f);
const float Rm = sqrtf(v * GAUSS_TRUNCATE);
- if(r >= Rm)
+ if (r >= Rm) {
return 0.0f;
-
+ }
return expf(-r * r / (2.0f * v)) / (2.0f * M_PI * v);
}
@@ -535,20 +535,20 @@ static float cubic_profile(float r, float radius, float sharpness)
{
float Rm = radius * (1.0f + sharpness);
- if(r >= Rm)
+ if (r >= Rm) {
return 0.0f;
-
+ }
/* custom variation with extra sharpness, to match the previous code */
- const float y = 1.0f/(1.0f + sharpness);
+ const float y = 1.0f / (1.0f + sharpness);
float Rmy, ry, ryinv;
Rmy = powf(Rm, y);
ry = powf(r, y);
- ryinv = (r > 0.0f)? powf(r, y - 1.0f): 0.0f;
+ ryinv = (r > 0.0f) ? powf(r, y - 1.0f) : 0.0f;
- const float Rmy5 = (Rmy*Rmy) * (Rmy*Rmy) * Rmy;
+ const float Rmy5 = (Rmy * Rmy) * (Rmy * Rmy) * Rmy;
const float f = Rmy - ry;
- const float num = f*(f*f)*(y*ryinv);
+ const float num = f * (f * f) * (y * ryinv);
return (10.0f * num) / (Rmy5 * M_PI);
}
@@ -576,7 +576,7 @@ static float eval_integral(float x0, float x1, short falloff_type, float sharpne
const float step = range / INTEGRAL_RESOLUTION;
float integral = 0.0f;
- for(int i = 0; i < INTEGRAL_RESOLUTION; ++i) {
+ for (int i = 0; i < INTEGRAL_RESOLUTION; ++i) {
float x = x0 + range * ((float)i + 0.5f) / (float)INTEGRAL_RESOLUTION;
float y = eval_profile(x, falloff_type, sharpness, param);
integral += y * step;
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index 030b0808b54..4e1161148ea 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -115,6 +115,76 @@ enum {
/* add any future new id property types here.*/
+
+/* Static ID override structs. */
+
+typedef struct IDOverrideStaticPropertyOperation {
+ struct IDOverrideStaticPropertyOperation *next, *prev;
+
+ /* Type of override. */
+ short operation;
+ short flag;
+ short pad_s1[2];
+
+ /* Sub-item references, if needed (for arrays or collections only).
+ * We need both reference and local values to allow e.g. insertion into collections (constraints, modifiers...).
+ * In collection case, if names are defined, they are used in priority.
+ * Names are pointers (instead of char[64]) to save some space, NULL when unset.
+ * Indices are -1 when unset. */
+ char *subitem_reference_name;
+ char *subitem_local_name;
+ int subitem_reference_index;
+ int subitem_local_index;
+} IDOverrideStaticPropertyOperation;
+
+/* IDOverridePropertyOperation->operation. */
+enum {
+ /* Basic operations. */
+ IDOVERRIDESTATIC_OP_NOOP = 0, /* Special value, forbids any overriding. */
+
+ IDOVERRIDESTATIC_OP_REPLACE = 1, /* Fully replace local value by reference one. */
+
+ /* Numeric-only operations. */
+ IDOVERRIDESTATIC_OP_ADD = 101, /* Add local value to reference one. */
+ /* Subtract local value from reference one (needed due to unsigned values etc.). */
+ IDOVERRIDESTATIC_OP_SUBTRACT = 102,
+ /* Multiply reference value by local one (more useful than diff for scales and the like). */
+ IDOVERRIDESTATIC_OP_MULTIPLY = 103,
+
+ /* Collection-only operations. */
+ IDOVERRIDESTATIC_OP_INSERT_AFTER = 201, /* Insert after given reference's subitem. */
+ IDOVERRIDESTATIC_OP_INSERT_BEFORE = 202, /* Insert before given reference's subitem. */
+ /* We can add more if needed (move, delete, ...). */
+};
+
+/* IDOverridePropertyOperation->flag. */
+enum {
+ IDOVERRIDESTATIC_FLAG_MANDATORY = 1 << 0, /* User cannot remove that override operation. */
+ IDOVERRIDESTATIC_FLAG_LOCKED = 1 << 1, /* User cannot change that override operation. */
+};
+
+/* A single overriden property, contain all operations on this one. */
+typedef struct IDOverrideStaticProperty {
+ struct IDOverrideStaticProperty *next, *prev;
+
+ /* Path from ID to overridden property. *Does not* include indices/names for final arrays/collections items. */
+ char *rna_path;
+
+ ListBase operations; /* List of overriding operations (IDOverridePropertyOperation) applied to this property. */
+} IDOverrideStaticProperty;
+
+/* Main container for all overriding data info of a data-block. */
+typedef struct IDOverrideStatic {
+ struct ID *reference; /* Reference linked ID which this one overrides. */
+ ListBase properties; /* List of IDOverrideProperty structs. */
+
+ /* Read/write data. */
+ /* Temp ID storing extra override data (used for differential operations only currently).
+ * Always NULL outside of read/write context. */
+ struct ID *storage;
+} IDOverrideStatic;
+
+
/* watch it: Sequence has identical beginning. */
/**
* ID is the first thing included in all serializable types. It
@@ -142,7 +212,12 @@ typedef struct ID {
int us;
int icon_id;
IDProperty *properties;
+
+ IDOverrideStatic *override_static; /* Reference linked ID which this one overrides. */
+
void *py_instance;
+
+ void *pad1;
} ID;
/**
@@ -309,7 +384,8 @@ typedef enum ID_Type {
/* id->flag (persitent). */
enum {
- LIB_FAKEUSER = 1 << 9,
+ LIB_OVERRIDE_STATIC_AUTO = 1 << 0, /* Allow automatic generation of overriding rules. */
+ LIB_FAKEUSER = 1 << 9,
};
/**
@@ -344,6 +420,9 @@ enum {
/* RESET_NEVER tag datablock as a place-holder (because the real one could not be linked from its library e.g.). */
LIB_TAG_MISSING = 1 << 6,
+ /* RESET_NEVER tag datablock as being up-to-date regarding its reference. */
+ LIB_TAG_OVERRIDESTATIC_OK = 1 << 9,
+
/* tag datablock has having an extra user. */
LIB_TAG_EXTRAUSER = 1 << 2,
/* tag datablock has having actually increased usercount for the extra virtual user. */
@@ -353,7 +432,7 @@ enum {
* Also used internally in readfile.c to mark datablocks needing do_versions. */
LIB_TAG_NEW = 1 << 8,
/* RESET_BEFORE_USE free test flag.
- * TODO make it a RESET_AFTER_USE too. */
+ * TODO make it a RESET_AFTER_USE too. */
LIB_TAG_DOIT = 1 << 10,
/* RESET_AFTER_USE tag existing data before linking so we know what is new. */
LIB_TAG_PRE_EXISTING = 1 << 11,
diff --git a/source/blender/makesdna/DNA_group_types.h b/source/blender/makesdna/DNA_group_types.h
index 45dd0cb9ff2..8f15aa85e97 100644
--- a/source/blender/makesdna/DNA_group_types.h
+++ b/source/blender/makesdna/DNA_group_types.h
@@ -60,6 +60,13 @@ typedef struct Group {
* on the last used scene */
unsigned int layer;
float dupli_ofs[3];
+
+ struct SceneCollection *collection;
+ struct ViewLayer *view_layer;
} Group;
+
+#define GROUP_MASTER_COLLECTION(_group) \
+ (((LayerCollection *)(_group)->view_layer->layer_collections.first)->scene_collection)
+
#endif /* __DNA_GROUP_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h
index 3eac7f0aab3..c677383cb6e 100644
--- a/source/blender/makesdna/DNA_layer_types.h
+++ b/source/blender/makesdna/DNA_layer_types.h
@@ -104,7 +104,8 @@ typedef struct SceneCollection {
char name[64]; /* MAX_NAME */
char filter[64]; /* MAX_NAME */
int active_object_index; /* for UI */
- int pad;
+ char type;
+ char pad[3];
ListBase objects; /* (Object *)LinkData->data */
ListBase filter_objects; /* (Object *)LinkData->data */
ListBase scene_collections; /* nested collections */
@@ -134,6 +135,11 @@ enum {
VIEW_LAYER_FREESTYLE = (1 << 2),
};
+/* SceneCollection->type */
+enum {
+ COLLECTION_TYPE_NONE = 0,
+ COLLECTION_TYPE_GROUP_INTERNAL = 1,
+};
/* *************************************************************** */
/* Engine Settings */
diff --git a/source/blender/makesdna/DNA_lightprobe_types.h b/source/blender/makesdna/DNA_lightprobe_types.h
index e65c36672b5..75705f7dd37 100644
--- a/source/blender/makesdna/DNA_lightprobe_types.h
+++ b/source/blender/makesdna/DNA_lightprobe_types.h
@@ -54,6 +54,9 @@ typedef struct LightProbe {
float clipsta, clipend;
+ float vis_bias, vis_bleedbias; /* VSM visibility biases */
+ float vis_blur, pad2;
+
int grid_resolution_x; /* Irradiance grid resolution */
int grid_resolution_y;
int grid_resolution_z;
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index 6187a46dcd7..78c623f6408 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -279,7 +279,7 @@ typedef struct Object {
struct BulletSoftBody *bsoft; /* settings for game engine bullet soft body */
char restrictflag; /* for restricting view, select, render etc. accessible in outliner */
- char recalc; /* dependency flag */
+ char pad3;
short softflag; /* softbody settings */
float anisotropicFriction[3];
@@ -326,7 +326,7 @@ typedef struct Object {
struct IDProperty *base_collection_properties; /* used by depsgraph, flushed from base */
ListBase drawdata; /* runtime, ObjectEngineData */
- int deg_update_flag; /* what has been updated in this object */
+ int pad1;
int select_color;
/* Mesh structure createrd during object evaluaiton.
@@ -371,6 +371,7 @@ typedef struct DupliObject {
struct ParticleSystem *particle_system;
unsigned int random_id;
unsigned int pad;
+ struct IDProperty *collection_properties;
} DupliObject;
/* **************** OBJECT ********************* */
@@ -531,9 +532,13 @@ enum {
/* also needed for base!!!!! or rather, they interfere....*/
/* base->flag and ob->flag */
-#define BA_WAS_SEL (1 << 1)
-#define BA_HAS_RECALC_OB (1 << 2)
-#define BA_HAS_RECALC_DATA (1 << 3)
+enum {
+ BA_WAS_SEL = (1 << 1),
+ /* NOTE: BA_HAS_RECALC_DATA can be re-used later if freed in readfile.c. */
+ // BA_HAS_RECALC_OB = (1 << 2), /* DEPRECATED */
+ // BA_HAS_RECALC_DATA = (1 << 3), /* DEPRECATED */
+ BA_SNAP_FIX_DEPS_FIASCO = (1 << 2), /* Yes, re-use deprecated bit, all fine since it's runtime only. */
+};
/* NOTE: this was used as a proper setting in past, so nullify before using */
#define BA_TEMP_TAG (1 << 5)
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
index 74a1a13c2eb..b7e118d2053 100644
--- a/source/blender/makesdna/DNA_sequence_types.h
+++ b/source/blender/makesdna/DNA_sequence_types.h
@@ -301,6 +301,11 @@ enum {
SEQ_TEXT_ALIGN_Y_BOTTOM = 2,
};
+typedef struct ColorMixVars {
+ int blend_effect; /* value from SEQ_TYPE_XXX enumeration */
+ float factor; /* blend factor [0.0f, 1.0f] */
+} ColorMixVars;
+
/* ***************** Sequence modifiers ****************** */
typedef struct SequenceModifierData {
@@ -516,8 +521,29 @@ enum {
SEQ_TYPE_ADJUSTMENT = 31,
SEQ_TYPE_GAUSSIAN_BLUR = 40,
SEQ_TYPE_TEXT = 41,
-
- SEQ_TYPE_MAX = 41
+ SEQ_TYPE_COLORMIX = 42,
+
+ /* Blend modes */
+ SEQ_TYPE_SCREEN = 43,
+ SEQ_TYPE_LIGHTEN = 44,
+ SEQ_TYPE_DODGE = 45,
+ SEQ_TYPE_DARKEN = 46,
+ SEQ_TYPE_BURN = 47,
+ SEQ_TYPE_LINEAR_BURN = 48,
+ SEQ_TYPE_OVERLAY = 49,
+ SEQ_TYPE_HARD_LIGHT = 50,
+ SEQ_TYPE_SOFT_LIGHT = 51,
+ SEQ_TYPE_PIN_LIGHT = 52,
+ SEQ_TYPE_LIN_LIGHT = 53,
+ SEQ_TYPE_VIVID_LIGHT = 54,
+ SEQ_TYPE_HUE = 55,
+ SEQ_TYPE_SATURATION = 56,
+ SEQ_TYPE_VALUE = 57,
+ SEQ_TYPE_BLEND_COLOR = 58,
+ SEQ_TYPE_DIFFERENCE = 59,
+ SEQ_TYPE_EXCLUSION = 60,
+
+ SEQ_TYPE_MAX = 60
};
#define SEQ_MOVIECLIP_RENDER_UNDISTORTED (1 << 0)
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 69086def4b9..27e108b82ab 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -126,7 +126,9 @@ typedef struct SpaceButs {
short preview; /* preview is signal to refresh */
/* texture context selector (material, lamp, particles, world, other) */
short texture_context, texture_context_prev;
- char flag, pad[7];
+ char flag;
+ char collection_context;
+ char pad[6];
void *path; /* runtime */
int pathflag, dataicon; /* runtime */
@@ -208,6 +210,12 @@ typedef enum eSpaceButtons_Texture_Context {
SB_TEXC_LINESTYLE = 5,
} eSpaceButtons_Texture_Context;
+/* sbuts->collection_context */
+typedef enum eSpaceButtons_Collection_Context {
+ SB_COLLECTION_CTX_VIEW_LAYER = 0,
+ SB_COLLECTION_CTX_GROUP = 1,
+} eSpaceButtons_Collection_Context;
+
/* sbuts->align */
typedef enum eSpaceButtons_Align {
BUT_FREE = 0,
@@ -711,6 +719,8 @@ typedef enum eFileSel_Action {
} eFileSel_Action;
/* sfile->params->flag and simasel->flag */
+/* Note: short flag, also used as 16 lower bits of flags in link/append code
+ * (WM and BLO code area, see BLO_LibLinkFlags in BLO_readfile.h). */
typedef enum eFileSel_Params_Flag {
FILE_SHOWSHORT = (1 << 0),
FILE_RELPATH = (1 << 1), /* was FILE_STRINGCODE */
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 3cdb379040c..81f605b093a 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -140,6 +140,8 @@ typedef struct uiWidgetStateColors {
char inner_key_sel[4];
char inner_driven[4];
char inner_driven_sel[4];
+ char inner_overridden[4];
+ char inner_overridden_sel[4];
float blend, pad;
} uiWidgetStateColors;
diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h
index 8a313d8eda9..3792873db31 100644
--- a/source/blender/makesdna/DNA_windowmanager_types.h
+++ b/source/blender/makesdna/DNA_windowmanager_types.h
@@ -41,6 +41,7 @@
struct wmWindowManager;
struct wmWindow;
+struct wmMsgBus;
struct wmEvent;
struct wmGesture;
struct wmOperatorType;
@@ -156,6 +157,9 @@ typedef struct wmWindowManager {
char is_interface_locked; /* indicates whether interface is locked for user interaction */
char par[7];
+
+ struct wmMsgBus *message_bus;
+
} wmWindowManager;
/* wmWindowManager.initialized */
diff --git a/source/blender/makesdna/DNA_workspace_types.h b/source/blender/makesdna/DNA_workspace_types.h
index 1fc6acb8c2c..adc3c1fef2b 100644
--- a/source/blender/makesdna/DNA_workspace_types.h
+++ b/source/blender/makesdna/DNA_workspace_types.h
@@ -84,6 +84,7 @@ typedef struct WorkSpace {
/* Store for each hook (so for each window) which layout has
* been activated the last time this workspace was visible. */
ListBase hook_layout_relations DNA_PRIVATE_WORKSPACE_READ_WRITE; /* WorkSpaceDataRelation */
+ ListBase scene_viewlayer_relations DNA_PRIVATE_WORKSPACE_READ_WRITE; /* WorkSpaceDataRelation */
/* Custom transform orientations */
ListBase transform_orientations DNA_PRIVATE_WORKSPACE;
@@ -94,7 +95,7 @@ typedef struct WorkSpace {
/* should be: '#ifdef USE_WORKSPACE_TOOL'. */
bToolDef tool;
- struct ViewLayer *view_layer DNA_PRIVATE_WORKSPACE;
+ struct ViewLayer *view_layer DNA_DEPRECATED;
struct ViewRender view_render;
} WorkSpace;
diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c
index 182a026df94..593d93b5615 100644
--- a/source/blender/makesdna/intern/makesdna.c
+++ b/source/blender/makesdna/intern/makesdna.c
@@ -993,7 +993,7 @@ static int make_structDNA(const char *baseDirectory, FILE *file, FILE *file_offs
char str[SDNA_MAX_FILENAME_LENGTH], *cp;
int firststruct;
- if (debugSDNA > -1) {
+ if (debugSDNA > 0) {
fflush(stdout);
printf("Running makesdna at debug level %d\n", debugSDNA);
}
@@ -1089,7 +1089,7 @@ static int make_structDNA(const char *baseDirectory, FILE *file, FILE *file_offs
/* file writing */
- if (debugSDNA > -1) printf("Writing file ... ");
+ if (debugSDNA > 0) printf("Writing file ... ");
if (nr_names == 0 || nr_structs == 0) {
/* pass */
@@ -1199,7 +1199,7 @@ static int make_structDNA(const char *baseDirectory, FILE *file, FILE *file_offs
MEM_freeN(typelens_64);
MEM_freeN(structs);
- if (debugSDNA > -1) printf("done.\n");
+ if (debugSDNA > 0) printf("done.\n");
return(0);
}
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index aedc53512b7..a99541385d0 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -39,6 +39,9 @@ extern "C" {
struct bContext;
struct ID;
+struct IDOverrideStatic;
+struct IDOverrideStaticProperty;
+struct IDOverrideStaticPropertyOperation;
struct ListBase;
struct Main;
struct ReportList;
@@ -118,6 +121,7 @@ extern StructRNA RNA_ColorManagedViewSettings;
extern StructRNA RNA_ColorRamp;
extern StructRNA RNA_ColorRampElement;
extern StructRNA RNA_ColorSequence;
+extern StructRNA RNA_ColorMixSequence;
extern StructRNA RNA_CompositorNode;
extern StructRNA RNA_CompositorNodeAlphaOver;
extern StructRNA RNA_CompositorNodeBilateralblur;
@@ -737,6 +741,7 @@ extern StructRNA RNA_XorController;
void RNA_main_pointer_create(struct Main *main, PointerRNA *r_ptr);
void RNA_id_pointer_create(struct ID *id, PointerRNA *r_ptr);
void RNA_pointer_create(struct ID *id, StructRNA *type, void *data, PointerRNA *r_ptr);
+bool RNA_pointer_is_null(const PointerRNA *ptr);
bool RNA_path_resolved_create(
PointerRNA *ptr, struct PropertyRNA *prop,
@@ -1042,7 +1047,7 @@ char *RNA_path_property_py(struct PointerRNA *ptr, struct PropertyRNA *prop, int
* call RNA_struct_find_property. The names have to exist as RNA properties
* for the type in the pointer, if they do not exist an error will be printed.
*
- * There is no support for pointers and collections here yet, these can be
+ * There is no support for pointers and collections here yet, these can be
* added when ID properties support them. */
int RNA_boolean_get(PointerRNA *ptr, const char *name);
@@ -1140,7 +1145,7 @@ bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop);
void RNA_property_unset(PointerRNA *ptr, PropertyRNA *prop);
bool RNA_struct_property_is_set_ex(PointerRNA *ptr, const char *identifier, bool use_ghost);
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier);
-bool RNA_property_is_idprop(PropertyRNA *prop);
+bool RNA_property_is_idprop(const PropertyRNA *prop);
bool RNA_property_is_unlink(PropertyRNA *prop);
void RNA_struct_property_unset(PointerRNA *ptr, const char *identifier);
@@ -1209,9 +1214,8 @@ int RNA_function_call_direct_va(struct bContext *C, struct ReportList *reports,
int RNA_function_call_direct_va_lookup(struct bContext *C, struct ReportList *reports, PointerRNA *ptr,
const char *identifier, const char *format, va_list args);
-const char *RNA_translate_ui_text(const char *text, const char *text_ctxt,
- struct StructRNA *type, struct PropertyRNA *prop,
- int translate);
+const char *RNA_translate_ui_text(
+ const char *text, const char *text_ctxt, struct StructRNA *type, struct PropertyRNA *prop, int translate);
/* ID */
@@ -1235,17 +1239,51 @@ StructRNA *ID_code_to_RNA_type(short idcode);
void _RNA_warning(const char *format, ...) ATTR_PRINTF_FORMAT(1, 2);
-/* Equals test (skips pointers and collections)
- * is_strict false assumes uninitialized properties are equal */
+/* Equals test. */
-typedef enum eRNAEqualsMode {
- RNA_EQ_STRICT, /* set/unset ignored */
- RNA_EQ_UNSET_MATCH_ANY, /* unset property matches anything */
- RNA_EQ_UNSET_MATCH_NONE /* unset property never matches set property */
-} eRNAEqualsMode;
+/* Note: In practice, EQ_STRICT and EQ_COMPARE have same behavior currently, and will yield same result. */
+typedef enum eRNACompareMode {
+ /* Only care about equality, not full comparison. */
+ RNA_EQ_STRICT, /* set/unset ignored */
+ RNA_EQ_UNSET_MATCH_ANY, /* unset property matches anything */
+ RNA_EQ_UNSET_MATCH_NONE, /* unset property never matches set property */
+ /* Full comparison. */
+ RNA_EQ_COMPARE,
+} eRNACompareMode;
-bool RNA_property_equals(struct PointerRNA *a, struct PointerRNA *b, struct PropertyRNA *prop, eRNAEqualsMode mode);
-bool RNA_struct_equals(struct PointerRNA *a, struct PointerRNA *b, eRNAEqualsMode mode);
+bool RNA_property_equals(struct PointerRNA *a, struct PointerRNA *b, struct PropertyRNA *prop, eRNACompareMode mode);
+bool RNA_struct_equals(struct PointerRNA *a, struct PointerRNA *b, eRNACompareMode mode);
+
+/* Override. */
+
+bool RNA_struct_override_matches(struct PointerRNA *local, struct PointerRNA *reference,
+ struct IDOverrideStatic *override, const bool ignore_non_overridable, const bool ignore_overridden);
+
+bool RNA_struct_override_store(
+ struct PointerRNA *local, struct PointerRNA *reference, PointerRNA *storage, struct IDOverrideStatic *override);
+
+void RNA_property_override_apply(
+ struct PointerRNA *dst, struct PointerRNA *src, struct PointerRNA *storage, struct PropertyRNA *prop,
+ struct IDOverrideStaticProperty *op);
+void RNA_struct_override_apply(
+ struct PointerRNA *dst, struct PointerRNA *src, struct PointerRNA *storage,
+ struct IDOverrideStatic *override);
+
+bool RNA_struct_auto_override(
+ struct PointerRNA *local, struct PointerRNA *reference, struct IDOverrideStatic *override, const char *root_path);
+
+struct IDOverrideStaticProperty *RNA_property_override_property_find(PointerRNA *ptr, PropertyRNA *prop);
+struct IDOverrideStaticProperty *RNA_property_override_property_get(PointerRNA *ptr, PropertyRNA *prop, bool *r_created);
+
+struct IDOverrideStaticPropertyOperation *RNA_property_override_property_operation_find(
+ PointerRNA *ptr, PropertyRNA *prop, const int index, const bool strict, bool *r_strict);
+struct IDOverrideStaticPropertyOperation *RNA_property_override_property_operation_get(
+ PointerRNA *ptr, PropertyRNA *prop, const short operation, const int index,
+ const bool strict, bool *r_strict, bool *r_created);
+
+void RNA_property_override_status(
+ PointerRNA *ptr, PropertyRNA *prop, const int index,
+ bool *r_overridable, bool *r_overridden, bool *r_mandatory, bool *r_locked);
#ifdef __cplusplus
}
diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h
index e9e4276b235..4e32651d356 100644
--- a/source/blender/makesrna/RNA_define.h
+++ b/source/blender/makesrna/RNA_define.h
@@ -177,6 +177,8 @@ void RNA_def_property_update(PropertyRNA *prop, int noteflag, const char *update
void RNA_def_property_editable_func(PropertyRNA *prop, const char *editable);
void RNA_def_property_editable_array_func(PropertyRNA *prop, const char *editable);
+void RNA_def_property_override_funcs(PropertyRNA *prop, const char *diff, const char *store, const char *apply);
+
void RNA_def_property_update_runtime(PropertyRNA *prop, const void *func);
void RNA_def_property_poll_runtime(PropertyRNA *prop, const void *func);
diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h
index 155c82bbbc3..345c47ae1bf 100644
--- a/source/blender/makesrna/RNA_enum_types.h
+++ b/source/blender/makesrna/RNA_enum_types.h
@@ -61,6 +61,8 @@ extern const EnumPropertyItem rna_enum_object_modifier_type_items[];
extern const EnumPropertyItem rna_enum_constraint_type_items[];
extern const EnumPropertyItem rna_enum_boidrule_type_items[];
extern const EnumPropertyItem rna_enum_sequence_modifier_type_items[];
+
+extern const EnumPropertyItem rna_enum_collection_type_items[];
extern const EnumPropertyItem rna_enum_layer_collection_mode_settings_type_items[];
extern const EnumPropertyItem rna_enum_modifier_triangulate_quad_method_items[];
diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h
index 657eeeeaeab..47aebbc13e7 100644
--- a/source/blender/makesrna/RNA_types.h
+++ b/source/blender/makesrna/RNA_types.h
@@ -108,6 +108,8 @@ typedef enum PropertyUnit {
#define RNA_TRANSLATION_PREC_DEFAULT 5
+#define RNA_STACK_ARRAY 32
+
/* also update enums in bpy_props.c when adding items here
* watch it: these values are written to files as part of
* node socket button subtypes!
@@ -156,7 +158,7 @@ typedef enum PropertySubType {
/* Make sure enums are updated with these */
/* HIGHEST FLAG IN USE: 1 << 31
- * FREE FLAGS: 2, 3, 7, 9, 11, 13, 14, 15, 30 */
+ * FREE FLAGS: 3, 7, 9, 11, 13, 14, 15, 30 */
typedef enum PropertyFlag {
/* editable means the property is editable in the user
* interface, properties are editable by default except
@@ -174,6 +176,9 @@ typedef enum PropertyFlag {
* and collections */
PROP_ANIMATABLE = (1 << 1),
+ /* Means the property can be overriden by a local 'proxy' of some linked datablock. */
+ PROP_OVERRIDABLE_STATIC = (1 << 2),
+
/* This flag means when the property's widget is in 'textedit' mode, it will be updated
* after every typed char, instead of waiting final validation. Used e.g. for text searchbox.
* It will also cause UI_BUT_VALUE_CLEAR to be set for text buttons. We could add an own flag
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index 293cef52b90..19f66109665 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -46,6 +46,14 @@
# endif
#endif
+/**
+ * Variable to control debug output of makesrna.
+ * debugSRNA:
+ * - 0 = no output, except errors
+ * - 1 = detail actions
+ */
+static int debugSRNA = 0;
+
/* stub for BLI_abort() */
#ifndef NDEBUG
void BLI_system_backtrace(FILE *fp)
@@ -62,7 +70,9 @@ void BLI_system_backtrace(FILE *fp)
static int file_older(const char *file1, const char *file2)
{
struct stat st1, st2;
- /* printf("compare: %s %s\n", file1, file2); */
+ if (debugSRNA > 0) {
+ printf("compare: %s %s\n", file1, file2);
+ }
if (stat(file1, &st1)) return 0;
if (stat(file2, &st2)) return 0;
@@ -3015,12 +3025,15 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
prop->arraylength[1],
prop->arraylength[2],
prop->totarraylength);
- fprintf(f, "\t%s%s, %d, %s, %s,\n",
+ fprintf(f, "\t%s%s, %d, %s, %s, %s, %s, %s,\n",
(prop->flag & PROP_CONTEXT_UPDATE) ? "(UpdateFunc)" : "",
rna_function_string(prop->update),
prop->noteflag,
rna_function_string(prop->editable),
- rna_function_string(prop->itemeditable));
+ rna_function_string(prop->itemeditable),
+ rna_function_string(prop->override_diff),
+ rna_function_string(prop->override_store),
+ rna_function_string(prop->override_apply));
if (prop->flag_internal & PROP_INTERN_RAW_ACCESS) rna_set_raw_offset(f, srna, prop);
else fprintf(f, "\t0, -1");
@@ -4141,7 +4154,9 @@ int main(int argc, char **argv)
return_status = 1;
}
else {
- fprintf(stderr, "Running makesrna\n");
+ if (debugSRNA > 0) {
+ fprintf(stderr, "Running makesrna\n");
+ }
makesrna_path = argv[0];
return_status = rna_preprocess(argv[1]);
}
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index c519c61e9e9..44df8916796 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -97,6 +97,7 @@ const EnumPropertyItem rna_enum_id_type_items[] = {
#include "BKE_idprop.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
+#include "BKE_library_override.h"
#include "BKE_library_remap.h"
#include "BKE_animsys.h"
#include "BKE_material.h"
@@ -311,6 +312,15 @@ static ID *rna_ID_copy(ID *id, Main *bmain)
return NULL;
}
+static ID *rna_ID_override_create(ID *id, Main *bmain)
+{
+ if (id->lib == NULL) {
+ return NULL;
+ }
+
+ return BKE_override_static_create_from(bmain, id);
+}
+
static void rna_ID_update_tag(ID *id, ReportList *reports, int flag)
{
/* XXX, new function for this! */
@@ -762,6 +772,14 @@ static PointerRNA rna_IDPreview_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_ImagePreview, prv_img);
}
+static PointerRNA rna_ID_override_reference_get(PointerRNA *ptr)
+{
+ ID *id = (ID *)ptr->data;
+ ID *reference = (id && id->override_static) ? id->override_static->reference : NULL;
+
+ return reference ? rna_pointer_inherit_refine(ptr, ID_code_to_RNA_type(GS(reference->name)), reference) : PointerRNA_NULL;
+}
+
#else
static void rna_def_ID_properties(BlenderRNA *brna)
@@ -1024,6 +1042,12 @@ static void rna_def_ID(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Library", "Library file the data-block is linked from");
+ prop = RNA_def_pointer(srna, "override_static_reference", "ID",
+ "Override Reference", "Reference linked data-block overridden by this one");
+ RNA_def_property_pointer_sdna(prop, NULL, "override_static->reference");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_pointer_funcs(prop, "rna_ID_override_reference_get", NULL, NULL, NULL);
+
prop = RNA_def_pointer(srna, "preview", "ImagePreview", "Preview",
"Preview image and icon of this data-block (None if not supported for this type of data)");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1036,6 +1060,12 @@ static void rna_def_ID(BlenderRNA *brna)
parm = RNA_def_pointer(func, "id", "ID", "", "New copy of the ID");
RNA_def_function_return(func, parm);
+ func = RNA_def_function(srna, "override_create", "rna_ID_override_create");
+ RNA_def_function_ui_description(func, "Create an overridden local copy of this linked data-block (not supported for all data-blocks)");
+ RNA_def_function_flag(func, FUNC_USE_MAIN);
+ parm = RNA_def_pointer(func, "id", "ID", "", "New overridden local copy of the ID");
+ RNA_def_function_return(func, parm);
+
func = RNA_def_function(srna, "user_clear", "rna_ID_user_clear");
RNA_def_function_ui_description(func, "Clear the user count of a data-block so its not saved, "
"on reload the data will be removed");
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 9c510176bb2..345c3d23dbe 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -51,6 +51,7 @@
#include "BKE_idprop.h"
#include "BKE_fcurve.h"
#include "BKE_library.h"
+#include "BKE_library_override.h"
#include "BKE_main.h"
#include "BKE_report.h"
@@ -61,6 +62,7 @@
#include "RNA_enum_types.h"
#include "WM_api.h"
+#include "WM_message.h"
/* flush updates */
#include "DNA_object_types.h"
@@ -173,6 +175,11 @@ void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr)
}
}
+bool RNA_pointer_is_null(const PointerRNA *ptr)
+{
+ return !((ptr->data != NULL) && (ptr->id.data != NULL) && (ptr->type != NULL));
+}
+
static void rna_pointer_inherit_id(StructRNA *type, PointerRNA *parent, PointerRNA *ptr)
{
if (type && type->flag & STRUCT_ID) {
@@ -1817,7 +1824,8 @@ bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop)
return ((flag & PROP_EDITABLE) &&
(flag & PROP_REGISTER) == 0 &&
- (!id || !ID_IS_LINKED(id) || (prop->flag & PROP_LIB_EXCEPTION)));
+ (!id || ((!ID_IS_LINKED(id) || (prop->flag & PROP_LIB_EXCEPTION)) &&
+ (!id->override_static || (prop->flag & PROP_OVERRIDABLE_STATIC)))));
}
/**
@@ -1843,11 +1851,19 @@ bool RNA_property_editable_info(PointerRNA *ptr, PropertyRNA *prop, const char *
}
/* property from linked data-block */
- if (id && ID_IS_LINKED(id) && (prop->flag & PROP_LIB_EXCEPTION) == 0) {
- if (!(*r_info)[0]) {
- *r_info = "Can't edit this property from a linked data-block.";
+ if (id) {
+ if (ID_IS_LINKED(id) && (prop->flag & PROP_LIB_EXCEPTION) == 0) {
+ if (!(*r_info)[0]) {
+ *r_info = "Can't edit this property from a linked data-block.";
+ }
+ return false;
+ }
+ if (id->override_static != NULL && (prop->flag & PROP_OVERRIDABLE_STATIC) == 0) {
+ if (!(*r_info)[0]) {
+ *r_info = "Can't edit this property from an override data-block.";
+ }
+ return false;
}
- return false;
}
return ((flag & PROP_EDITABLE) && (flag & PROP_REGISTER) == 0);
@@ -1966,8 +1982,18 @@ static void rna_property_update(bContext *C, Main *bmain, Scene *scene, PointerR
else
prop->update(bmain, scene, ptr);
}
+#if 0
if (prop->noteflag)
WM_main_add_notifier(prop->noteflag, ptr->id.data);
+#else
+ /* if C is NULL, we're updating from animation.
+ * avoid slow-down from f-curves by not publishing (for now). */
+ if (C != NULL) {
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ /* we could add NULL check, for now don't */
+ WM_msg_publish_rna(mbus, ptr, prop);
+ }
+#endif
}
if (!is_rna || (prop->flag & PROP_IDPROPERTY)) {
@@ -2921,9 +2947,6 @@ char *RNA_property_string_get_alloc(PointerRNA *ptr, PropertyRNA *prop,
int length;
BLI_assert(RNA_property_type(prop) == PROP_STRING);
- if (!ptr->data) {
- return NULL;
- }
length = RNA_property_string_length(ptr, prop);
@@ -5687,7 +5710,7 @@ void RNA_struct_property_unset(PointerRNA *ptr, const char *identifier)
}
}
-bool RNA_property_is_idprop(PropertyRNA *prop)
+bool RNA_property_is_idprop(const PropertyRNA *prop)
{
return (prop->magic != RNA_MAGIC);
}
@@ -6860,8 +6883,7 @@ int RNA_function_call_direct_va_lookup(bContext *C, ReportList *reports, Pointer
}
const char *RNA_translate_ui_text(
- const char *text, const char *text_ctxt, StructRNA *type, PropertyRNA *prop,
- int translate)
+ const char *text, const char *text_ctxt, StructRNA *type, PropertyRNA *prop, int translate)
{
return rna_translate_ui_text(text, text_ctxt, type, prop, translate);
}
@@ -6963,120 +6985,22 @@ bool RNA_property_reset(PointerRNA *ptr, PropertyRNA *prop, int index)
}
}
+static bool rna_property_override_operation_apply(
+ PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, PropertyRNA *prop_local,
+ IDOverrideStaticPropertyOperation *opop);
+
bool RNA_property_copy(PointerRNA *ptr, PointerRNA *fromptr, PropertyRNA *prop, int index)
{
- int len, fromlen;
- PropertyRNA *fromprop = prop;
-
- if (prop->magic != RNA_MAGIC) {
- /* In case of IDProperty, we have to find the *real* idprop of ptr,
- * since prop in this case is just a fake wrapper around actual IDProp data, and not a 'real' PropertyRNA. */
- prop = (PropertyRNA *)rna_idproperty_find(ptr, ((IDProperty *)fromprop)->name);
-
- /* its possible the custom-prop doesn't exist on this data-block */
- if (prop == NULL) {
- return false;
- }
-
- /* Even though currently we now prop will always be the 'fromprop', this might not be the case in the future. */
- if (prop == fromprop) {
- fromprop = (PropertyRNA *)rna_idproperty_find(fromptr, ((IDProperty *)prop)->name);
- }
- }
-
- /* get the length of the array to work with */
- len = RNA_property_array_length(ptr, prop);
- fromlen = RNA_property_array_length(fromptr, fromprop);
-
- if (len != fromlen)
+ if (!RNA_property_editable(ptr, prop)) {
return false;
-
- /* get and set the default values as appropriate for the various types */
- switch (RNA_property_type(prop)) {
- case PROP_BOOLEAN:
- if (len) {
- if (index == -1) {
- int *tmparray = MEM_callocN(sizeof(int) * len, "copy - boolean");
-
- RNA_property_boolean_get_array(fromptr, fromprop, tmparray);
- RNA_property_boolean_set_array(ptr, prop, tmparray);
-
- MEM_freeN(tmparray);
- }
- else {
- int value = RNA_property_boolean_get_index(fromptr, fromprop, index);
- RNA_property_boolean_set_index(ptr, prop, index, value);
- }
- }
- else {
- int value = RNA_property_boolean_get(fromptr, fromprop);
- RNA_property_boolean_set(ptr, prop, value);
- }
- return true;
- case PROP_INT:
- if (len) {
- if (index == -1) {
- int *tmparray = MEM_callocN(sizeof(int) * len, "copy - int");
-
- RNA_property_int_get_array(fromptr, fromprop, tmparray);
- RNA_property_int_set_array(ptr, prop, tmparray);
-
- MEM_freeN(tmparray);
- }
- else {
- int value = RNA_property_int_get_index(fromptr, fromprop, index);
- RNA_property_int_set_index(ptr, prop, index, value);
- }
- }
- else {
- int value = RNA_property_int_get(fromptr, fromprop);
- RNA_property_int_set(ptr, prop, value);
- }
- return true;
- case PROP_FLOAT:
- if (len) {
- if (index == -1) {
- float *tmparray = MEM_callocN(sizeof(float) * len, "copy - float");
-
- RNA_property_float_get_array(fromptr, fromprop, tmparray);
- RNA_property_float_set_array(ptr, prop, tmparray);
-
- MEM_freeN(tmparray);
- }
- else {
- float value = RNA_property_float_get_index(fromptr, fromprop, index);
- RNA_property_float_set_index(ptr, prop, index, value);
- }
- }
- else {
- float value = RNA_property_float_get(fromptr, fromprop);
- RNA_property_float_set(ptr, prop, value);
- }
- return true;
- case PROP_ENUM:
- {
- int value = RNA_property_enum_get(fromptr, fromprop);
- RNA_property_enum_set(ptr, prop, value);
- return true;
- }
- case PROP_POINTER:
- {
- PointerRNA value = RNA_property_pointer_get(fromptr, fromprop);
- RNA_property_pointer_set(ptr, prop, value);
- return true;
- }
- case PROP_STRING:
- {
- char *value = RNA_property_string_get_alloc(fromptr, fromprop, NULL, 0, NULL);
- RNA_property_string_set(ptr, prop, value);
- MEM_freeN(value);
- return true;
- }
- default:
- return false;
}
- return false;
+ IDOverrideStaticPropertyOperation opop = {
+ .operation = IDOVERRIDESTATIC_OP_REPLACE,
+ .subitem_reference_index = index,
+ .subitem_local_index = index
+ };
+ return rna_property_override_operation_apply(ptr, fromptr, NULL, prop, &opop);
}
/* use RNA_warning macro which includes __func__ suffix */
@@ -7101,176 +7025,513 @@ void _RNA_warning(const char *format, ...)
#endif
}
-bool RNA_property_equals(PointerRNA *a, PointerRNA *b, PropertyRNA *prop, eRNAEqualsMode mode)
+static int rna_property_override_diff(
+ PointerRNA *a, PointerRNA *b, PropertyRNA *prop, eRNACompareMode mode,
+ IDOverrideStatic *override, const char *rna_path, bool *r_override_changed, const int flags);
+
+bool RNA_property_equals(PointerRNA *a, PointerRNA *b, PropertyRNA *prop, eRNACompareMode mode)
+{
+ BLI_assert(ELEM(mode, RNA_EQ_STRICT, RNA_EQ_UNSET_MATCH_ANY, RNA_EQ_UNSET_MATCH_NONE));
+
+ return (rna_property_override_diff(a, b, prop, mode, NULL, NULL, NULL, 0) != 0);
+}
+
+bool RNA_struct_equals(PointerRNA *a, PointerRNA *b, eRNACompareMode mode)
+{
+ CollectionPropertyIterator iter;
+ PropertyRNA *iterprop;
+ bool equals = true;
+
+ if (a == NULL && b == NULL)
+ return true;
+ else if (a == NULL || b == NULL)
+ return false;
+ else if (a->type != b->type)
+ return false;
+
+ iterprop = RNA_struct_iterator_property(a->type);
+
+ RNA_property_collection_begin(a, iterprop, &iter);
+ for (; iter.valid; RNA_property_collection_next(&iter)) {
+ PropertyRNA *prop = iter.ptr.data;
+
+ if (!RNA_property_equals(a, b, prop, mode)) {
+ equals = false;
+ break;
+ }
+ }
+ RNA_property_collection_end(&iter);
+
+ return equals;
+}
+
+/* Low-level functions, also used by non-override RNA API like copy or equality check. */
+#include "PIL_time_utildefines.h"
+static int rna_property_override_diff(
+ PointerRNA *ptr_a, PointerRNA *ptr_b, PropertyRNA *prop_a, eRNACompareMode mode,
+ IDOverrideStatic *override, const char *rna_path, bool *r_override_changed, const int flags)
{
- int len, fromlen;
+ int len_a, len_b;
+
+ PropertyRNA *prop_b = prop_a;
+
+ if (prop_a->magic != RNA_MAGIC) {
+ /* In case of IDProperty, we have to find the *real* idprop of ptr,
+ * since prop in this case is just a fake wrapper around actual IDProp data, and not a 'real' PropertyRNA. */
+ /* XXX TODO this is ugly, we already get correct prop in upcalling code, whould just pass them to this func! */
+ prop_a = (PropertyRNA *)rna_idproperty_find(ptr_a, ((IDProperty *)prop_a)->name);
+ prop_b = (PropertyRNA *)rna_idproperty_find(ptr_b, ((IDProperty *)prop_b)->name);
+
+ if (ELEM(NULL, prop_a, prop_b)) {
+ return 1;
+ }
+ }
+
+ BLI_assert(prop_a->override_diff == prop_b->override_diff && prop_a->override_diff != NULL);
if (mode == RNA_EQ_UNSET_MATCH_ANY) {
/* uninitialized properties are assumed to match anything */
- if (!RNA_property_is_set(a, prop) || !RNA_property_is_set(b, prop))
- return true;
+ if (!RNA_property_is_set(ptr_a, prop_a) || !RNA_property_is_set(ptr_b, prop_b))
+ return 0;
}
else if (mode == RNA_EQ_UNSET_MATCH_NONE) {
/* unset properties never match set properties */
- if (RNA_property_is_set(a, prop) != RNA_property_is_set(b, prop))
- return false;
+ if (RNA_property_is_set(ptr_a, prop_a) != RNA_property_is_set(ptr_b, prop_b))
+ return 1;
}
/* get the length of the array to work with */
- len = RNA_property_array_length(a, prop);
- fromlen = RNA_property_array_length(b, prop);
+ len_a = RNA_property_array_length(ptr_a, prop_a);
+ len_b = RNA_property_array_length(ptr_b, prop_b);
- if (len != fromlen)
- return false;
+ if (len_a != len_b) {
+ /* Do not handle override in that case, we do not support insertion/deletion from arrays for now. */
+ return len_a > len_b ? 1 : -1;
+ }
- /* get and set the default values as appropriate for the various types */
- switch (RNA_property_type(prop)) {
- case PROP_BOOLEAN:
- {
- if (len) {
- int fixed_a[16], fixed_b[16];
- int *array_a, *array_b;
- bool equals;
+ return prop_a->override_diff(
+ ptr_a, ptr_b, prop_a, prop_b, len_a, len_b, mode, override, rna_path, flags, r_override_changed);
+}
- array_a = (len > 16) ? MEM_mallocN(sizeof(int) * len, "RNA equals") : fixed_a;
- array_b = (len > 16) ? MEM_mallocN(sizeof(int) * len, "RNA equals") : fixed_b;
+/* Modify local data-block to make it ready for override application (only needed for diff operations, where we use
+ * the local data-block's data as second operand). */
+static bool rna_property_override_operation_store(
+ PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, PropertyRNA *prop_local,
+ IDOverrideStaticProperty *op)
+{
+ int len_local, len_reference, len_storage = 0;
+ PropertyRNA *prop_reference = prop_local;
+ PropertyRNA *prop_storage = prop_local;
+ bool changed = false;
- RNA_property_boolean_get_array(a, prop, array_a);
- RNA_property_boolean_get_array(b, prop, array_b);
+ if (!ptr_storage) {
+ return changed;
+ }
- equals = memcmp(array_a, array_b, sizeof(int) * len) == 0;
+ if (prop_local->magic != RNA_MAGIC) {
+ /* In case of IDProperty, we have to find the *real* idprop of ptr,
+ * since prop in this case is just a fake wrapper around actual IDProp data, and not a 'real' PropertyRNA. */
+ /* XXX TODO this is ugly, we already get correct prop in upcalling code, should just pass them to this func! */
+ prop_local = (PropertyRNA *)rna_idproperty_find(ptr_local, ((IDProperty *)prop_local)->name);
+ prop_reference = (PropertyRNA *)rna_idproperty_find(ptr_reference, ((IDProperty *)prop_reference)->name);
+ if (ptr_storage) {
+ prop_storage = (PropertyRNA *)rna_idproperty_find(ptr_storage, ((IDProperty *)prop_storage)->name);
+ }
- if (array_a != fixed_a) MEM_freeN(array_a);
- if (array_b != fixed_b) MEM_freeN(array_b);
+ /* its possible the custom-prop doesn't exist on this data-block */
+ if (prop_local == NULL) {
+ return changed;
+ }
+ }
- return equals;
- }
- else {
- int value = RNA_property_boolean_get(a, prop);
- return value == RNA_property_boolean_get(b, prop);
- }
+ /* get the length of the array to work with */
+ len_local = RNA_property_array_length(ptr_local, prop_local);
+ len_reference = RNA_property_array_length(ptr_reference, prop_reference);
+ if (prop_storage) {
+ len_storage = RNA_property_array_length(ptr_storage, prop_storage);
+ }
+
+ if (len_local != len_reference || len_local != len_storage) {
+ /* Do not handle override in that case, we do not support insertion/deletion from arrays for now. */
+ return changed;
+ }
+
+ BLI_assert(prop_local->override_store == prop_reference->override_store &&
+ (!ptr_storage || prop_local->override_store == prop_storage->override_store) &&
+ prop_local->override_store != NULL);
+
+ for (IDOverrideStaticPropertyOperation *opop = op->operations.first; opop; opop = opop->next) {
+ /* Only needed for diff operations. */
+ if (!ELEM(opop->operation, IDOVERRIDESTATIC_OP_ADD, IDOVERRIDESTATIC_OP_SUBTRACT, IDOVERRIDESTATIC_OP_MULTIPLY)) {
+ continue;
}
- case PROP_INT:
+ if (prop_local->override_store(
+ ptr_local, ptr_reference, ptr_storage, prop_local, prop_reference, prop_storage,
+ len_local, len_reference, len_storage, opop))
{
- if (len) {
- int fixed_a[16], fixed_b[16];
- int *array_a, *array_b;
- bool equals;
+ changed = true;
+ }
+ }
- array_a = (len > 16) ? MEM_mallocN(sizeof(int) * len, "RNA equals") : fixed_a;
- array_b = (len > 16) ? MEM_mallocN(sizeof(int) * len, "RNA equals") : fixed_b;
+ return changed;
+}
- RNA_property_int_get_array(a, prop, array_a);
- RNA_property_int_get_array(b, prop, array_b);
+static bool rna_property_override_operation_apply(
+ PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, PropertyRNA *prop_local,
+ IDOverrideStaticPropertyOperation *opop)
+{
+ int len_local, len_reference, len_storage = 0;
+ PropertyRNA *prop_reference = prop_local;
+ PropertyRNA *prop_storage = prop_local;
- equals = memcmp(array_a, array_b, sizeof(int) * len) == 0;
+ const short override_op = opop->operation;
- if (array_a != fixed_a) MEM_freeN(array_a);
- if (array_b != fixed_b) MEM_freeN(array_b);
+ if (override_op == IDOVERRIDESTATIC_OP_NOOP) {
+ return true;
+ }
- return equals;
- }
- else {
- int value = RNA_property_int_get(a, prop);
- return value == RNA_property_int_get(b, prop);
- }
+ if (ELEM(override_op, IDOVERRIDESTATIC_OP_ADD, IDOVERRIDESTATIC_OP_SUBTRACT, IDOVERRIDESTATIC_OP_MULTIPLY) && !ptr_storage) {
+ /* We cannot apply 'diff' override operations without some refference storage.
+ * This should typically only happen at read time of .blend file... */
+ return false;
+ }
+
+ if (prop_local->magic != RNA_MAGIC) {
+ /* In case of IDProperty, we have to find the *real* idprop of ptr,
+ * since prop in this case is just a fake wrapper around actual IDProp data, and not a 'real' PropertyRNA. */
+ /* XXX TODO this is ugly, we already get correct prop in upcalling code, whould just pass them to this func! */
+ prop_local = (PropertyRNA *)rna_idproperty_find(ptr_local, ((IDProperty *)prop_local)->name);
+ prop_reference = (PropertyRNA *)rna_idproperty_find(ptr_reference, ((IDProperty *)prop_reference)->name);
+ if (ptr_storage) {
+ prop_storage = (PropertyRNA *)rna_idproperty_find(ptr_storage, ((IDProperty *)prop_storage)->name);
}
- case PROP_FLOAT:
- {
- if (len) {
- float fixed_a[16], fixed_b[16];
- float *array_a, *array_b;
- bool equals;
+ /* its possible the custom-prop doesn't exist on this data-block */
+ if (prop_local == NULL) {
+ return false;
+ }
+ }
- array_a = (len > 16) ? MEM_mallocN(sizeof(float) * len, "RNA equals") : fixed_a;
- array_b = (len > 16) ? MEM_mallocN(sizeof(float) * len, "RNA equals") : fixed_b;
+ if (ELEM(override_op, IDOVERRIDESTATIC_OP_ADD, IDOVERRIDESTATIC_OP_SUBTRACT, IDOVERRIDESTATIC_OP_MULTIPLY) && !prop_storage) {
+ /* We cannot apply 'diff' override operations without some refference storage.
+ * This should typically only happen at read time of .blend file... */
+ return false;
+ }
- RNA_property_float_get_array(a, prop, array_a);
- RNA_property_float_get_array(b, prop, array_b);
+ /* get the length of the array to work with */
+ len_local = RNA_property_array_length(ptr_local, prop_local);
+ len_reference = RNA_property_array_length(ptr_reference, prop_reference);
+ if (ptr_storage) {
+ len_storage = RNA_property_array_length(ptr_storage, prop_storage);
+ }
- equals = memcmp(array_a, array_b, sizeof(float) * len) == 0;
+ if (len_local != len_reference || (ptr_storage && len_local != len_storage)) {
+ /* Do not handle override in that case, we do not support insertion/deletion from arrays for now. */
+ return false;
+ }
- if (array_a != fixed_a) MEM_freeN(array_a);
- if (array_b != fixed_b) MEM_freeN(array_b);
+ BLI_assert(prop_local->override_apply == prop_reference->override_apply &&
+ (!ptr_storage || prop_local->override_apply == prop_storage->override_apply) &&
+ prop_local->override_apply != NULL);
- return equals;
- }
- else {
- float value = RNA_property_float_get(a, prop);
- return value == RNA_property_float_get(b, prop);
+ /* get and set the default values as appropriate for the various types */
+ return prop_local->override_apply(
+ ptr_local, ptr_reference, ptr_storage,
+ prop_local, prop_reference, prop_storage,
+ len_local, len_reference, len_storage,
+ opop);
+}
+
+
+/**
+ * Check whether reference and local overriden data match (are the same),
+ * with respect to given restrictive sets of properties. */
+bool RNA_struct_override_matches(
+ PointerRNA *local, PointerRNA *reference,
+ IDOverrideStatic *override, const bool ignore_non_overridable, const bool ignore_overridden)
+{
+ CollectionPropertyIterator iter;
+ PropertyRNA *iterprop;
+ bool equals = true;
+
+ BLI_assert(local->type == reference->type);
+
+ iterprop = RNA_struct_iterator_property(local->type);
+
+ RNA_property_collection_begin(local, iterprop, &iter);
+ for (; iter.valid; RNA_property_collection_next(&iter)) {
+ PropertyRNA *prop = iter.ptr.data;
+
+ if (ignore_non_overridable && !(prop->flag & PROP_OVERRIDABLE_STATIC)) {
+ continue;
+ }
+
+ if (ignore_overridden) {
+ /* XXX TODO this will have to be refined to handle collections insertions, and array items */
+ char *rna_path = RNA_path_from_ID_to_property(local, prop);
+ if (BKE_override_static_property_find(override, rna_path) != NULL) {
+ MEM_SAFE_FREE(rna_path);
+ continue;
}
+ MEM_SAFE_FREE(rna_path);
}
- case PROP_ENUM:
- {
- int value = RNA_property_enum_get(a, prop);
- return value == RNA_property_enum_get(b, prop);
+ int flag = 0;
+ if (ignore_non_overridable) {
+ flag |= RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE;
+ }
+ if (ignore_overridden) {
+ flag |= RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN;
+ }
+ if (rna_property_override_diff(local, reference, prop, RNA_EQ_STRICT, override, NULL, NULL, flag) != 0) {
+ equals = false;
+ break;
}
+ }
+ RNA_property_collection_end(&iter);
- case PROP_STRING:
- {
- char fixed_a[128], fixed_b[128];
- int len_a, len_b;
- char *value_a = RNA_property_string_get_alloc(a, prop, fixed_a, sizeof(fixed_a), &len_a);
- char *value_b = RNA_property_string_get_alloc(b, prop, fixed_b, sizeof(fixed_b), &len_b);
- bool equals = STREQ(value_a, value_b);
+ return equals;
+}
- if (value_a != fixed_a) MEM_freeN(value_a);
- if (value_b != fixed_b) MEM_freeN(value_b);
+/** Store needed second operands into \a storage data-block for differential override operations. */
+bool RNA_struct_override_store(PointerRNA *local, PointerRNA *reference, PointerRNA *storage, IDOverrideStatic *override)
+{
+ bool changed = false;
- return equals;
- }
+#ifdef DEBUG_OVERRIDE_TIMEIT
+ TIMEIT_START_AVERAGED(RNA_struct_override_store);
+#endif
+ for (IDOverrideStaticProperty *op = override->properties.first; op; op = op->next) {
+ /* Simplified for now! */
+ PointerRNA src_data, dst_data;
+ PropertyRNA *src_prop, *dst_prop;
- case PROP_POINTER:
+ if (RNA_path_resolve_property(reference, op->rna_path, &src_data, &src_prop) &&
+ RNA_path_resolve_property(local, op->rna_path, &dst_data, &dst_prop))
{
- if (!STREQ(RNA_property_identifier(prop), "rna_type")) {
- PointerRNA propptr_a = RNA_property_pointer_get(a, prop);
- PointerRNA propptr_b = RNA_property_pointer_get(b, prop);
- return RNA_struct_equals(&propptr_a, &propptr_b, mode);
+ PointerRNA storage_data;
+ PropertyRNA *storage_prop = NULL;
+
+ /* It is totally OK if this does not success, only a subset of override operations actually need storage. */
+ if (storage && (storage->id.data != NULL)) {
+ RNA_path_resolve_property(storage, op->rna_path, &storage_data, &storage_prop);
+ }
+
+ if (rna_property_override_operation_store(&dst_data, &src_data, &storage_data, src_prop, op)) {
+ changed = true;
}
- break;
}
+ }
+#ifdef DEBUG_OVERRIDE_TIMEIT
+ TIMEIT_END_AVERAGED(RNA_struct_override_store);
+#endif
- default:
- break;
+ return changed;
+}
+
+/** Apply given \a op override property operations on \a dst, using \a src as source. */
+void RNA_property_override_apply(
+ PointerRNA *dst, PointerRNA *src, PointerRNA *storage, PropertyRNA *prop, IDOverrideStaticProperty *op)
+{
+ for (IDOverrideStaticPropertyOperation *opop = op->operations.first; opop; opop = opop->next) {
+ if (!rna_property_override_operation_apply(dst, src, storage, prop, opop)) {
+ BLI_assert(0);
+ }
}
+}
- return true;
+/** Apply given \a override operations on \a dst, using \a src as source. */
+void RNA_struct_override_apply(PointerRNA *dst, PointerRNA *src, PointerRNA *storage, IDOverrideStatic *override)
+{
+#ifdef DEBUG_OVERRIDE_TIMEIT
+ TIMEIT_START_AVERAGED(RNA_struct_override_apply);
+#endif
+ for (IDOverrideStaticProperty *op = override->properties.first; op; op = op->next) {
+ /* Simplified for now! */
+ PointerRNA src_data, dst_data;
+ PropertyRNA *src_prop, *dst_prop;
+
+ if (RNA_path_resolve_property(src, op->rna_path, &src_data, &src_prop) &&
+ RNA_path_resolve_property(dst, op->rna_path, &dst_data, &dst_prop))
+ {
+ PointerRNA storage_data;
+ PropertyRNA *storage_prop = NULL;
+
+ /* It is totally OK if this does not success, only a subset of override operations actually need storage. */
+ if (storage && (storage->id.data != NULL)) {
+ RNA_path_resolve_property(storage, op->rna_path, &storage_data, &storage_prop);
+ }
+
+ /* Note that src and dst props are the same, unless they are IDProperties... */
+ RNA_property_override_apply(&dst_data, &src_data, storage_prop ? &storage_data : NULL, src_prop, op);
+ }
+#ifndef NDEBUG
+ else {
+ printf("Failed to apply static override operation to '%s.%s' (could not resolve some properties)\n",
+ ((ID *)src->id.data)->name, op->rna_path);
+ }
+#endif
+ }
+#ifdef DEBUG_OVERRIDE_TIMEIT
+ TIMEIT_END_AVERAGED(RNA_struct_override_apply);
+#endif
}
-bool RNA_struct_equals(PointerRNA *a, PointerRNA *b, eRNAEqualsMode mode)
+/** Automatically define override rules by comparing \a local and \a reference RNA structs. */
+bool RNA_struct_auto_override(PointerRNA *local, PointerRNA *reference, IDOverrideStatic *override, const char *root_path)
{
CollectionPropertyIterator iter;
-// CollectionPropertyRNA *citerprop; /* UNUSED */
PropertyRNA *iterprop;
- bool equals = true;
+ bool changed = false;
- if (a == NULL && b == NULL)
- return true;
- else if (a == NULL || b == NULL)
- return false;
- else if (a->type != b->type)
- return false;
+ BLI_assert(local->type == reference->type);
+ BLI_assert(local->id.data && reference->id.data);
- iterprop = RNA_struct_iterator_property(a->type);
-// citerprop = (CollectionPropertyRNA *)rna_ensure_property(iterprop); /* UNUSED */
+ if ((((ID *)local->id.data)->flag & LIB_OVERRIDE_STATIC_AUTO) == 0) {
+ return changed;
+ }
- RNA_property_collection_begin(a, iterprop, &iter);
- for (; iter.valid; RNA_property_collection_next(&iter)) {
+#ifdef DEBUG_OVERRIDE_TIMEIT
+ static float _sum_time = 0.0f;
+ static float _num_time = 0.0f;
+ double _timeit_time;
+ if (!root_path) {
+ _timeit_time = PIL_check_seconds_timer();
+ }
+#endif
+
+ iterprop = RNA_struct_iterator_property(local->type);
+
+ for (RNA_property_collection_begin(local, iterprop, &iter); iter.valid; RNA_property_collection_next(&iter)) {
PropertyRNA *prop = iter.ptr.data;
- if (!RNA_property_equals(a, b, prop, mode)) {
- equals = false;
- break;
+ if (!(prop->flag & PROP_OVERRIDABLE_STATIC)) {
+ continue;
+ }
+ if (RNA_property_animated(local, prop)) {
+ continue;
+ }
+
+ /* XXX TODO this will have to be refined to handle collections insertions, and array items */
+ char *rna_path;
+ if (root_path) {
+ /* Inlined building, much much more efficient. */
+ rna_path = BLI_sprintfN("%s.%s", root_path, RNA_property_identifier(prop));
+ }
+ else {
+ rna_path = RNA_path_from_ID_to_property(local, prop);
}
+ if (rna_path == NULL) {
+ continue;
+ }
+
+ rna_property_override_diff(local, reference, prop, RNA_EQ_STRICT, override, rna_path, &changed,
+ RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE | RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN);
+
+ MEM_SAFE_FREE(rna_path);
}
RNA_property_collection_end(&iter);
- return equals;
+#ifdef DEBUG_OVERRIDE_TIMEIT
+ if (!root_path) {
+ const float _delta_time = (float)(PIL_check_seconds_timer() - _timeit_time);
+ _sum_time += _delta_time;
+ _num_time++;
+ printf("ID: %s\n", ((ID *)local->id.data)->name);
+ printf("time end (%s): %.6f\n", __func__, _delta_time);
+ printf("time averaged (%s): %.6f (total: %.6f, in %d runs)\n", __func__, (_sum_time / _num_time), _sum_time, (int)_num_time);
+ }
+#endif
+
+ return changed;
+}
+
+IDOverrideStaticProperty *RNA_property_override_property_find(PointerRNA *ptr, PropertyRNA *prop)
+{
+ ID *id = ptr->id.data;
+
+ if (!id || !id->override_static) {
+ return NULL;
+ }
+
+ char *rna_path = RNA_path_from_ID_to_property(ptr, prop);
+ if (rna_path) {
+ IDOverrideStaticProperty *op = BKE_override_static_property_find(id->override_static, rna_path);
+ MEM_freeN(rna_path);
+ return op;
+ }
+ return NULL;
+}
+
+IDOverrideStaticProperty *RNA_property_override_property_get(PointerRNA *ptr, PropertyRNA *prop, bool *r_created)
+{
+ ID *id = ptr->id.data;
+
+ if (!id || !id->override_static) {
+ return NULL;
+ }
+
+ char *rna_path = RNA_path_from_ID_to_property(ptr, prop);
+ if (rna_path) {
+ IDOverrideStaticProperty *op = BKE_override_static_property_get(id->override_static, rna_path, r_created);
+ MEM_freeN(rna_path);
+ return op;
+ }
+ return NULL;
}
+IDOverrideStaticPropertyOperation *RNA_property_override_property_operation_find(
+ PointerRNA *ptr, PropertyRNA *prop, const int index, const bool strict, bool *r_strict)
+{
+ IDOverrideStaticProperty *op = RNA_property_override_property_find(ptr, prop);
+
+ if (!op) {
+ return NULL;
+ }
+
+ return BKE_override_static_property_operation_find(op, NULL, NULL, index, index, strict, r_strict);
+}
+
+IDOverrideStaticPropertyOperation *RNA_property_override_property_operation_get(
+ PointerRNA *ptr, PropertyRNA *prop, const short operation, const int index,
+ const bool strict, bool *r_strict, bool *r_created)
+{
+ IDOverrideStaticProperty *op = RNA_property_override_property_get(ptr, prop, NULL);
+
+ if (!op) {
+ return NULL;
+ }
+
+ return BKE_override_static_property_operation_get(op, operation, NULL, NULL, index, index, strict, r_strict, r_created);
+}
+
+void RNA_property_override_status(
+ PointerRNA *ptr, PropertyRNA *prop, const int index,
+ bool *r_overridable, bool *r_overridden, bool *r_mandatory, bool *r_locked)
+{
+#define SET_RET(_name, _val) if (_name != NULL) *_name = (_val)
+
+ SET_RET(r_overridable, false);
+ SET_RET(r_overridden, false);
+ SET_RET(r_mandatory, false);
+ SET_RET(r_locked, false);
+
+ if (!ptr || !prop || !ptr->id.data || !((ID *)ptr->id.data)->override_static) {
+ return;
+ }
+
+ SET_RET(r_overridable, (prop->flag & PROP_OVERRIDABLE_STATIC) && (prop->flag & PROP_EDITABLE));
+
+ if (r_overridden || r_mandatory || r_locked) {
+ IDOverrideStaticPropertyOperation *opop = RNA_property_override_property_operation_find(ptr, prop, index, false, NULL);
+ SET_RET(r_overridden, opop != NULL);
+ SET_RET(r_mandatory, (opop->flag & IDOVERRIDESTATIC_FLAG_MANDATORY) != 0);
+ SET_RET(r_locked, (opop->flag & IDOVERRIDESTATIC_FLAG_LOCKED) != 0);
+ }
+}
+
+
bool RNA_path_resolved_create(
PointerRNA *ptr, struct PropertyRNA *prop,
diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c
index e53533df782..3d11e7bb723 100644
--- a/source/blender/makesrna/intern/rna_animation.c
+++ b/source/blender/makesrna/intern/rna_animation.c
@@ -585,6 +585,34 @@ static FCurve *rna_Driver_find(AnimData *adt, ReportList *reports, const char *d
return list_find_fcurve(&adt->drivers, data_path, index);
}
+bool rna_AnimaData_override_apply(
+ PointerRNA *ptr_dst, PointerRNA *ptr_src, PointerRNA *ptr_storage,
+ PropertyRNA *prop_dst, PropertyRNA *prop_src, PropertyRNA *UNUSED(prop_storage),
+ const int len_dst, const int len_src, const int len_storage,
+ IDOverrideStaticPropertyOperation *opop)
+{
+ BLI_assert(len_dst == len_src && (!ptr_storage || len_dst == len_storage) && len_dst == 0);
+ BLI_assert(opop->operation == IDOVERRIDESTATIC_OP_REPLACE && "Unsupported RNA override operation on animdata pointer");
+ UNUSED_VARS_NDEBUG(ptr_storage, len_dst, len_src, len_storage, opop);
+
+ /* AnimData is a special case, since you cannot edit/replace it, it's either existent or not. */
+ AnimData *adt_dst = RNA_property_pointer_get(ptr_dst, prop_dst).data;
+ AnimData *adt_src = RNA_property_pointer_get(ptr_src, prop_src).data;
+
+ if (adt_dst == NULL && adt_src != NULL) {
+ /* Copy anim data from reference into final local ID. */
+ BKE_animdata_copy_id(NULL, ptr_dst->id.data, ptr_src->id.data, false);
+ return true;
+ }
+ else if (adt_dst != NULL && adt_src == NULL) {
+ /* Override has cleared/removed anim data from its reference. */
+ BKE_animdata_free(ptr_dst->id.data, true);
+ return true;
+ }
+
+ return false;
+}
+
#else
/* helper function for Keying Set -> keying settings */
@@ -999,6 +1027,8 @@ void rna_def_animdata_common(StructRNA *srna)
prop = RNA_def_property(srna, "animation_data", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "adt");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+ RNA_def_property_override_funcs(prop, NULL, NULL, "rna_AnimaData_override_apply");
RNA_def_property_ui_text(prop, "Animation Data", "Animation data for this data-block");
}
@@ -1022,7 +1052,7 @@ static void rna_def_animdata(BlenderRNA *brna)
/* Active Action */
prop = RNA_def_property(srna, "action", PROP_POINTER, PROP_NONE);
/* this flag as well as the dynamic test must be defined for this to be editable... */
- RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT | PROP_OVERRIDABLE_STATIC);
RNA_def_property_pointer_funcs(prop, NULL, "rna_AnimData_action_set", NULL, "rna_Action_id_poll");
RNA_def_property_editable_func(prop, "rna_AnimData_action_editable");
RNA_def_property_ui_text(prop, "Action", "Active Action for this data-block");
diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c
index f8a492c3cee..1ec0fd92a67 100644
--- a/source/blender/makesrna/intern/rna_armature.c
+++ b/source/blender/makesrna/intern/rna_armature.c
@@ -549,14 +549,14 @@ void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone)
RNA_def_property_float_sdna(prop, NULL, "ease1");
RNA_def_property_range(prop, -5.0f, 5.0f);
RNA_def_property_float_default(prop, 1.0f);
- RNA_def_property_ui_text(prop, "B-Bone Ease In", "Length of first Bezier Handle (for B-Bones only)");
+ RNA_def_property_ui_text(prop, "Ease In", "Length of first Bezier Handle (for B-Bones only)");
RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
prop = RNA_def_property(srna, "bbone_easeout", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "ease2");
RNA_def_property_range(prop, -5.0f, 5.0f);
RNA_def_property_float_default(prop, 1.0f);
- RNA_def_property_ui_text(prop, "B-Bone Ease Out", "Length of second Bezier Handle (for B-Bones only)");
+ RNA_def_property_ui_text(prop, "Ease Out", "Length of second Bezier Handle (for B-Bones only)");
RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
/* Scale In/Out */
diff --git a/source/blender/makesrna/intern/rna_context.c b/source/blender/makesrna/intern/rna_context.c
index 911f2cca2f6..3df114282fd 100644
--- a/source/blender/makesrna/intern/rna_context.c
+++ b/source/blender/makesrna/intern/rna_context.c
@@ -144,15 +144,15 @@ static PointerRNA rna_Context_view_render_get(PointerRNA *ptr)
static void rna_Context_engine_get(PointerRNA *ptr, char *value)
{
bContext *C = (bContext *)ptr->data;
- RenderEngineType *engine = CTX_data_engine(C);
- strcpy(value, engine->idname);
+ RenderEngineType *engine_type = CTX_data_engine_type(C);
+ strcpy(value, engine_type->idname);
}
static int rna_Context_engine_length(PointerRNA *ptr)
{
bContext *C = (bContext *)ptr->data;
- RenderEngineType *engine = CTX_data_engine(C);
- return strlen(engine->idname);
+ RenderEngineType *engine_type = CTX_data_engine_type(C);
+ return strlen(engine_type->idname);
}
static PointerRNA rna_Context_scene_collection_get(PointerRNA *ptr)
diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c
index c8a6a503fd9..03e58f8f78e 100644
--- a/source/blender/makesrna/intern/rna_define.c
+++ b/source/blender/makesrna/intern/rna_define.c
@@ -1270,6 +1270,14 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_, const char *identifier
#endif
}
+ /* Override handling. */
+ if (DefRNA.preprocess) {
+ prop->override_diff = (RNAPropOverrideDiff)"rna_property_override_diff_default";
+ prop->override_store = (RNAPropOverrideStore)"rna_property_override_store_default";
+ prop->override_apply = (RNAPropOverrideApply)"rna_property_override_apply_default";
+ }
+ /* TODO: do we want that for runtime-defined stuff too? I’d say no, but... maybe yes :/ */
+
rna_addtail(&cont->properties, prop);
return prop;
@@ -2222,6 +2230,29 @@ void RNA_def_property_editable_array_func(PropertyRNA *prop, const char *editabl
if (editable) prop->itemeditable = (ItemEditableFunc)editable;
}
+/**
+ * Set custom callbacks for override operations handling.
+ *
+ * \note \a diff callback will also be used by RNA comparison/equality functions.
+ */
+void RNA_def_property_override_funcs(PropertyRNA *prop, const char *diff, const char *store, const char *apply)
+{
+ if (!DefRNA.preprocess) {
+ fprintf(stderr, "%s: only during preprocessing.\n", __func__);
+ return;
+ }
+
+ if (diff) {
+ prop->override_diff = (RNAPropOverrideDiff)diff;
+ }
+ if (store) {
+ prop->override_store = (RNAPropOverrideStore)store;
+ }
+ if (apply) {
+ prop->override_apply = (RNAPropOverrideApply)apply;
+ }
+}
+
void RNA_def_property_update(PropertyRNA *prop, int noteflag, const char *func)
{
if (!DefRNA.preprocess) {
diff --git a/source/blender/makesrna/intern/rna_depsgraph.c b/source/blender/makesrna/intern/rna_depsgraph.c
index 04c8352833e..7d520ec6abd 100644
--- a/source/blender/makesrna/intern/rna_depsgraph.c
+++ b/source/blender/makesrna/intern/rna_depsgraph.c
@@ -61,7 +61,7 @@ static PointerRNA rna_DepsgraphIter_object_get(PointerRNA *ptr)
static PointerRNA rna_DepsgraphIter_instance_object_get(PointerRNA *ptr)
{
BLI_Iterator *iterator = ptr->data;
- DEGObjectsIteratorData *deg_iter = (DEGObjectsIteratorData *)iterator->data;
+ DEGOIterObjectData *deg_iter = (DEGOIterObjectData *)iterator->data;
Object *instance_object = NULL;
if (deg_iter->dupli_object_current != NULL) {
instance_object = deg_iter->dupli_object_current->ob;
@@ -72,7 +72,7 @@ static PointerRNA rna_DepsgraphIter_instance_object_get(PointerRNA *ptr)
static PointerRNA rna_DepsgraphIter_parent_get(PointerRNA *ptr)
{
BLI_Iterator *iterator = ptr->data;
- DEGObjectsIteratorData *deg_iter = (DEGObjectsIteratorData *)iterator->data;
+ DEGOIterObjectData *deg_iter = (DEGOIterObjectData *)iterator->data;
Object *dupli_parent = NULL;
if (deg_iter->dupli_object_current != NULL) {
dupli_parent = deg_iter->dupli_parent;
@@ -83,7 +83,7 @@ static PointerRNA rna_DepsgraphIter_parent_get(PointerRNA *ptr)
static void rna_DepsgraphIter_persistent_id_get(PointerRNA *ptr, int *persistent_id)
{
BLI_Iterator *iterator = ptr->data;
- DEGObjectsIteratorData *deg_iter = (DEGObjectsIteratorData *)iterator->data;
+ DEGOIterObjectData *deg_iter = (DEGOIterObjectData *)iterator->data;
memcpy(persistent_id, deg_iter->dupli_object_current->persistent_id,
sizeof(deg_iter->dupli_object_current->persistent_id));
}
@@ -91,7 +91,7 @@ static void rna_DepsgraphIter_persistent_id_get(PointerRNA *ptr, int *persistent
static void rna_DepsgraphIter_orco_get(PointerRNA *ptr, float *orco)
{
BLI_Iterator *iterator = ptr->data;
- DEGObjectsIteratorData *deg_iter = (DEGObjectsIteratorData *)iterator->data;
+ DEGOIterObjectData *deg_iter = (DEGOIterObjectData *)iterator->data;
memcpy(orco, deg_iter->dupli_object_current->orco,
sizeof(deg_iter->dupli_object_current->orco));
}
@@ -99,14 +99,14 @@ static void rna_DepsgraphIter_orco_get(PointerRNA *ptr, float *orco)
static unsigned int rna_DepsgraphIter_random_id_get(PointerRNA *ptr)
{
BLI_Iterator *iterator = ptr->data;
- DEGObjectsIteratorData *deg_iter = (DEGObjectsIteratorData *)iterator->data;
+ DEGOIterObjectData *deg_iter = (DEGOIterObjectData *)iterator->data;
return deg_iter->dupli_object_current->random_id;
}
static void rna_DepsgraphIter_uv_get(PointerRNA *ptr, float *uv)
{
BLI_Iterator *iterator = ptr->data;
- DEGObjectsIteratorData *deg_iter = (DEGObjectsIteratorData *)iterator->data;
+ DEGOIterObjectData *deg_iter = (DEGOIterObjectData *)iterator->data;
memcpy(uv, deg_iter->dupli_object_current->uv,
sizeof(deg_iter->dupli_object_current->uv));
}
@@ -114,7 +114,7 @@ static void rna_DepsgraphIter_uv_get(PointerRNA *ptr, float *uv)
static int rna_DepsgraphIter_is_instance_get(PointerRNA *ptr)
{
BLI_Iterator *iterator = ptr->data;
- DEGObjectsIteratorData *deg_iter = (DEGObjectsIteratorData *)iterator->data;
+ DEGOIterObjectData *deg_iter = (DEGOIterObjectData *)iterator->data;
return (deg_iter->dupli_object_current != NULL);
}
@@ -149,25 +149,25 @@ static void rna_Depsgraph_debug_stats(Depsgraph *graph, char *result)
static void rna_Depsgraph_objects_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
iter->internal.custom = MEM_callocN(sizeof(BLI_Iterator), __func__);
- DEGObjectsIteratorData *data = MEM_callocN(sizeof(DEGObjectsIteratorData), __func__);
+ DEGOIterObjectData *data = MEM_callocN(sizeof(DEGOIterObjectData), __func__);
data->graph = (Depsgraph *)ptr->data;
- data->flag = DEG_OBJECT_ITER_FLAG_SET;
+ data->flag = DEG_ITER_OBJECT_FLAG_SET;
((BLI_Iterator *)iter->internal.custom)->valid = true;
- DEG_objects_iterator_begin(iter->internal.custom, data);
+ DEG_iterator_objects_begin(iter->internal.custom, data);
iter->valid = ((BLI_Iterator *)iter->internal.custom)->valid;
}
static void rna_Depsgraph_objects_next(CollectionPropertyIterator *iter)
{
- DEG_objects_iterator_next(iter->internal.custom);
+ DEG_iterator_objects_next(iter->internal.custom);
iter->valid = ((BLI_Iterator *)iter->internal.custom)->valid;
}
static void rna_Depsgraph_objects_end(CollectionPropertyIterator *iter)
{
- DEG_objects_iterator_end(iter->internal.custom);
+ DEG_iterator_objects_end(iter->internal.custom);
MEM_freeN(((BLI_Iterator *)iter->internal.custom)->data);
MEM_freeN(iter->internal.custom);
}
@@ -186,25 +186,25 @@ static PointerRNA rna_Depsgraph_objects_get(CollectionPropertyIterator *iter)
static void rna_Depsgraph_duplis_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
iter->internal.custom = MEM_callocN(sizeof(BLI_Iterator), __func__);
- DEGObjectsIteratorData *data = MEM_callocN(sizeof(DEGObjectsIteratorData), __func__);
+ DEGOIterObjectData *data = MEM_callocN(sizeof(DEGOIterObjectData), __func__);
data->graph = (Depsgraph *)ptr->data;
- data->flag = DEG_OBJECT_ITER_FLAG_ALL;
+ data->flag = DEG_ITER_OBJECT_FLAG_ALL;
((BLI_Iterator *)iter->internal.custom)->valid = true;
- DEG_objects_iterator_begin(iter->internal.custom, data);
+ DEG_iterator_objects_begin(iter->internal.custom, data);
iter->valid = ((BLI_Iterator *)iter->internal.custom)->valid;
}
static void rna_Depsgraph_duplis_next(CollectionPropertyIterator *iter)
{
- DEG_objects_iterator_next(iter->internal.custom);
+ DEG_iterator_objects_next(iter->internal.custom);
iter->valid = ((BLI_Iterator *)iter->internal.custom)->valid;
}
static void rna_Depsgraph_duplis_end(CollectionPropertyIterator *iter)
{
- DEG_objects_iterator_end(iter->internal.custom);
+ DEG_iterator_objects_end(iter->internal.custom);
MEM_freeN(((BLI_Iterator *)iter->internal.custom)->data);
MEM_freeN(iter->internal.custom);
}
diff --git a/source/blender/makesrna/intern/rna_group.c b/source/blender/makesrna/intern/rna_group.c
index 2a5a0011279..bf64bb1181f 100644
--- a/source/blender/makesrna/intern/rna_group.c
+++ b/source/blender/makesrna/intern/rna_group.c
@@ -49,8 +49,9 @@ static PointerRNA rna_Group_objects_get(CollectionPropertyIterator *iter)
{
ListBaseIterator *internal = &iter->internal.listbase;
- /* we are actually iterating a GroupObject list, so override get */
- return rna_pointer_inherit_refine(&iter->parent, &RNA_Object, ((GroupObject *)internal->link)->ob);
+ /* we are actually iterating a ObjectBase list, so override get */
+ Base *base = (Base *)internal->link;
+ return rna_pointer_inherit_refine(&iter->parent, &RNA_Object, base->object);
}
static void rna_Group_objects_link(Group *group, ReportList *reports, Object *object)
@@ -124,20 +125,18 @@ void RNA_def_group(BlenderRNA *brna)
RNA_def_property_ui_range(prop, -10000.0, 10000.0, 10, RNA_TRANSLATION_PREC_DEFAULT);
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
- prop = RNA_def_property(srna, "layers", PROP_BOOLEAN, PROP_LAYER);
- RNA_def_property_boolean_sdna(prop, NULL, "layer", 1);
- RNA_def_property_array(prop, 20);
- RNA_def_property_ui_text(prop, "Dupli Layers", "Layers visible when this group is instanced as a dupli");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
-
prop = RNA_def_property(srna, "objects", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "gobject", NULL);
+ RNA_def_property_collection_sdna(prop, NULL, "view_layer->object_bases", NULL);
RNA_def_property_struct_type(prop, "Object");
RNA_def_property_ui_text(prop, "Objects", "A collection of this groups objects");
RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, "rna_Group_objects_get", NULL, NULL, NULL, NULL);
-
rna_def_group_objects(brna, prop);
+ prop = RNA_def_property(srna, "view_layer", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "ViewLayer");
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "View Layer", "Group internal view layer");
}
#endif
diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c
index d516692ec28..212a8bb8e20 100644
--- a/source/blender/makesrna/intern/rna_image.c
+++ b/source/blender/makesrna/intern/rna_image.c
@@ -669,6 +669,7 @@ static void rna_def_image(BlenderRNA *brna)
RNA_def_struct_ui_icon(srna, ICON_IMAGE_DATA);
prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
RNA_def_property_string_sdna(prop, NULL, "name");
RNA_def_property_ui_text(prop, "File Name", "Image/Movie file name");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_reload_update");
@@ -708,6 +709,7 @@ static void rna_def_image(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Packed Files", "Collection of packed images");
prop = RNA_def_property(srna, "field_order", PROP_ENUM, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
RNA_def_property_enum_items(prop, prop_field_order_items);
RNA_def_property_ui_text(prop, "Field Order", "Order of video fields (select which lines are displayed first)");
@@ -715,6 +717,7 @@ static void rna_def_image(BlenderRNA *brna)
/* booleans */
prop = RNA_def_property(srna, "use_fields", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_FIELDS);
RNA_def_property_ui_text(prop, "Fields", "Use fields of the image");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_fields_update");
@@ -722,36 +725,43 @@ static void rna_def_image(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_view_as_render", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_VIEW_AS_RENDER);
RNA_def_property_ui_text(prop, "View as Render", "Apply render part of display transformation when displaying this image on the screen");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
prop = RNA_def_property(srna, "use_alpha", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", IMA_IGNORE_ALPHA);
RNA_def_property_ui_text(prop, "Use Alpha", "Use the alpha channel information from the image or make image fully opaque");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_colormanage_update");
prop = RNA_def_property(srna, "use_deinterlace", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_DEINTERLACE);
RNA_def_property_ui_text(prop, "Deinterlace", "Deinterlace movie file on load");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_reload_update");
prop = RNA_def_property(srna, "use_multiview", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_USE_VIEWS);
RNA_def_property_ui_text(prop, "Use Multi-View", "Use Multiple Views (when available)");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_views_format_update");
prop = RNA_def_property(srna, "is_stereo_3d", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
RNA_def_property_boolean_funcs(prop, "rna_Image_is_stereo_3d_get", NULL);
RNA_def_property_ui_text(prop, "Stereo 3D", "Image has left and right views");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "is_multiview", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
RNA_def_property_boolean_funcs(prop, "rna_Image_is_multiview_get", NULL);
RNA_def_property_ui_text(prop, "Multiple Views", "Image has more than one view");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "is_dirty", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
RNA_def_property_boolean_funcs(prop, "rna_Image_dirty_get", NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Dirty", "Image has changed and is not saved");
@@ -795,12 +805,14 @@ static void rna_def_image(BlenderRNA *brna)
/* realtime properties */
prop = RNA_def_property(srna, "mapping", PROP_ENUM, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
RNA_def_property_enum_items(prop, prop_mapping_items);
RNA_def_property_ui_text(prop, "Mapping", "Mapping type to use for this image in the game engine");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
prop = RNA_def_property(srna, "display_aspect", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
RNA_def_property_float_sdna(prop, NULL, "aspx");
RNA_def_property_array(prop, 2);
RNA_def_property_range(prop, 0.1f, FLT_MAX);
@@ -809,52 +821,61 @@ static void rna_def_image(BlenderRNA *brna)
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
prop = RNA_def_property(srna, "use_animation", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
RNA_def_property_boolean_sdna(prop, NULL, "tpageflag", IMA_TWINANIM);
RNA_def_property_ui_text(prop, "Animated", "Use as animated texture in the game engine");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_animated_update");
prop = RNA_def_property(srna, "frame_start", PROP_INT, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
RNA_def_property_int_sdna(prop, NULL, "twsta");
RNA_def_property_range(prop, 0, 255);
RNA_def_property_ui_text(prop, "Animation Start", "Start frame of an animated texture");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_animated_update");
prop = RNA_def_property(srna, "frame_end", PROP_INT, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
RNA_def_property_int_sdna(prop, NULL, "twend");
RNA_def_property_range(prop, 0, 255);
RNA_def_property_ui_text(prop, "Animation End", "End frame of an animated texture");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_animated_update");
prop = RNA_def_property(srna, "fps", PROP_INT, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
RNA_def_property_int_sdna(prop, NULL, "animspeed");
RNA_def_property_range(prop, 1, 100);
RNA_def_property_ui_text(prop, "Animation Speed", "Speed of the animation in frames per second");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
prop = RNA_def_property(srna, "use_tiles", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
RNA_def_property_boolean_sdna(prop, NULL, "tpageflag", IMA_TILES);
RNA_def_property_ui_text(prop, "Tiles",
"Use of tilemode for faces (default shift-LMB to pick the tile for selected faces)");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
prop = RNA_def_property(srna, "tiles_x", PROP_INT, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
RNA_def_property_int_sdna(prop, NULL, "xrep");
RNA_def_property_range(prop, 1, 16);
RNA_def_property_ui_text(prop, "Tiles X", "Degree of repetition in the X direction");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
prop = RNA_def_property(srna, "tiles_y", PROP_INT, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
RNA_def_property_int_sdna(prop, NULL, "yrep");
RNA_def_property_range(prop, 1, 16);
RNA_def_property_ui_text(prop, "Tiles Y", "Degree of repetition in the Y direction");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
prop = RNA_def_property(srna, "use_clamp_x", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
RNA_def_property_boolean_sdna(prop, NULL, "tpageflag", IMA_CLAMP_U);
RNA_def_property_ui_text(prop, "Clamp X", "Disable texture repeating horizontally");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
prop = RNA_def_property(srna, "use_clamp_y", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
RNA_def_property_boolean_sdna(prop, NULL, "tpageflag", IMA_CLAMP_V);
RNA_def_property_ui_text(prop, "Clamp Y", "Disable texture repeating vertically");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
@@ -893,6 +914,7 @@ static void rna_def_image(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_float_vector(srna, "resolution", 2, NULL, 0, 0, "Resolution", "X/Y pixels per meter", 0, 0);
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
RNA_def_property_float_funcs(prop, "rna_Image_resolution_get", "rna_Image_resolution_set", NULL);
prop = RNA_def_property(srna, "frame_duration", PROP_INT, PROP_UNSIGNED);
@@ -927,12 +949,14 @@ static void rna_def_image(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Color Space Settings", "Input color space settings");
prop = RNA_def_property(srna, "alpha_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
RNA_def_property_enum_items(prop, alpha_mode_items);
RNA_def_property_ui_text(prop, "Alpha Mode", "Representation of alpha information in the RGBA pixels");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_colormanage_update");
/* multiview */
prop = RNA_def_property(srna, "views_format", PROP_ENUM, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
RNA_def_property_enum_sdna(prop, NULL, "views_format");
RNA_def_property_enum_items(prop, rna_enum_views_format_items);
RNA_def_property_ui_text(prop, "Views Format", "Mode to load image views");
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index 23a34918d33..7dffab4eefb 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -37,6 +37,9 @@
struct FreestyleSettings;
struct ID;
+struct IDOverrideStatic;
+struct IDOverrideStaticProperty;
+struct IDOverrideStaticPropertyOperation;
struct IDProperty;
struct Main;
struct Mesh;
@@ -201,6 +204,12 @@ void RNA_def_mask(struct BlenderRNA *brna);
void rna_def_animdata_common(struct StructRNA *srna);
+bool rna_AnimaData_override_apply(
+ struct PointerRNA *ptr_local, struct PointerRNA *ptr_reference, struct PointerRNA *ptr_storage,
+ struct PropertyRNA *prop_local, struct PropertyRNA *prop_reference, struct PropertyRNA *prop_storage,
+ const int len_local, const int len_reference, const int len_storage,
+ struct IDOverrideStaticPropertyOperation *opop);
+
void rna_def_animviz_common(struct StructRNA *srna);
void rna_def_motionpath_common(struct StructRNA *srna);
@@ -391,6 +400,33 @@ extern StructRNA RNA_PropertyGroup;
struct IDProperty *rna_idproperty_check(struct PropertyRNA **prop, struct PointerRNA *ptr);
+/* Override default callbacks. */
+/* Default override callbacks for all types. */
+/* TODO: Maybe at some point we'll want to write that in direct RNA-generated code instead
+ * (like we do for default get/set/etc.)?
+ * Not obvious though, those are fairly more complicated than basic SDNA access.
+ */
+int rna_property_override_diff_default(
+ struct PointerRNA *ptr_a, struct PointerRNA *ptr_b,
+ struct PropertyRNA *prop_a, struct PropertyRNA *prop_b,
+ const int len_a, const int len_b,
+ const int mode,
+ struct IDOverrideStatic *override, const char *rna_path,
+ const int flags, bool *r_override_changed);
+
+bool rna_property_override_store_default(
+ struct PointerRNA *ptr_local, struct PointerRNA *ptr_reference, struct PointerRNA *ptr_storage,
+ struct PropertyRNA *prop_local, struct PropertyRNA *prop_reference, struct PropertyRNA *prop_storage,
+ const int len_local, const int len_reference, const int len_storage,
+ struct IDOverrideStaticPropertyOperation *opop);
+
+bool rna_property_override_apply_default(
+ struct PointerRNA *ptr_dst, struct PointerRNA *ptr_src, struct PointerRNA *ptr_storage,
+ struct PropertyRNA *prop_dst, struct PropertyRNA *prop_src, struct PropertyRNA *prop_storage,
+ const int len_dst, const int len_src, const int len_storage,
+ struct IDOverrideStaticPropertyOperation *opop);
+
+
/* Builtin Property Callbacks */
void rna_builtin_properties_begin(struct CollectionPropertyIterator *iter, struct PointerRNA *ptr);
diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h
index b43423464e9..fd0b655e41e 100644
--- a/source/blender/makesrna/intern/rna_internal_types.h
+++ b/source/blender/makesrna/intern/rna_internal_types.h
@@ -40,6 +40,9 @@ struct PointerRNA;
struct FunctionRNA;
struct CollectionPropertyIterator;
struct bContext;
+struct IDOverrideStatic;
+struct IDOverrideStaticProperty;
+struct IDOverrideStaticPropertyOperation;
struct IDProperty;
struct GHash;
struct Main;
@@ -117,6 +120,60 @@ typedef void (*PropStringSetFuncEx)(struct PointerRNA *ptr, struct PropertyRNA *
typedef int (*PropEnumGetFuncEx)(struct PointerRNA *ptr, struct PropertyRNA *prop);
typedef void (*PropEnumSetFuncEx)(struct PointerRNA *ptr, struct PropertyRNA *prop, int value);
+/* Handling override operations, and also comparison. */
+enum {
+ /* Do not compare properties that are not overridable. */
+ RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE = 1 << 0,
+ /* Do not compare properties that are already overridden. */
+ RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN = 1 << 1,
+};
+
+/**
+ * If \a override is NULL, merely do comparison between prop_a from ptr_a and prop_b from ptr_b,
+ * following comparison mode given.
+ * If \a override and \a rna_path are not NULL, it will add a new override operation for overridable properties
+ * that differ and have not yet been overridden (and set accordingly \a r_override_changed if given).
+ *
+ * \note Given PropertyRNA are final (in case of IDProps...).
+ * \note In non-array cases, \a len values are 0.
+ * \note \a override, \a rna_path and \a r_override_changed may be NULL pointers.
+ */
+typedef int (*RNAPropOverrideDiff)(
+ struct PointerRNA *ptr_a, struct PointerRNA *ptr_b,
+ struct PropertyRNA *prop_a, struct PropertyRNA *prop_b,
+ const int len_a, const int len_b,
+ const int mode,
+ struct IDOverrideStatic *override, const char *rna_path,
+ const int flags, bool *r_override_changed);
+
+/**
+ * Only used for differential override (add, sub, etc.).
+ * Store into storage the value needed to transform reference's value into local's value.
+ *
+ * \note Given PropertyRNA are final (in case of IDProps...).
+ * \note In non-array cases, \a len values are 0.
+ * \note Might change given override operation (e.g. change 'add' one into 'sub'), in case computed storage value
+ * is out of range (or even change it to basic 'set' operation if nothing else works).
+ */
+typedef bool (*RNAPropOverrideStore)(
+ struct PointerRNA *ptr_local, struct PointerRNA *ptr_reference, struct PointerRNA *ptr_storage,
+ struct PropertyRNA *prop_local, struct PropertyRNA *prop_reference, struct PropertyRNA *prop_storage,
+ const int len_local, const int len_reference, const int len_storage,
+ struct IDOverrideStaticPropertyOperation *opop);
+
+/**
+ * Apply given override operation from src to dst (using value from storage as second operand
+ * for differential operations).
+ *
+ * \note Given PropertyRNA are final (in case of IDProps...).
+ * \note In non-array cases, \a len values are 0.
+ */
+typedef bool (*RNAPropOverrideApply)(
+ struct PointerRNA *ptr_dst, struct PointerRNA *ptr_src, struct PointerRNA *ptr_storage,
+ struct PropertyRNA *prop_dst, struct PropertyRNA *prop_src, struct PropertyRNA *prop_storage,
+ const int len_dst, const int len_src, const int len_storage,
+ struct IDOverrideStaticPropertyOperation *opop);
+
/* Container - generic abstracted container of RNA properties */
typedef struct ContainerRNA {
void *next, *prev;
@@ -194,6 +251,11 @@ struct PropertyRNA {
/* callback for testing if array-item editable (if applicable) */
ItemEditableFunc itemeditable;
+ /* Override handling callbacks (diff is also used for comparison). */
+ RNAPropOverrideDiff override_diff;
+ RNAPropOverrideStore override_store;
+ RNAPropOverrideApply override_apply;
+
/* raw access */
int rawoffset;
RawPropertyType rawtype;
diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c
index 4583774318b..877d6b250c0 100644
--- a/source/blender/makesrna/intern/rna_layer.c
+++ b/source/blender/makesrna/intern/rna_layer.c
@@ -54,8 +54,15 @@ const EnumPropertyItem rna_enum_layer_collection_mode_settings_type_items[] = {
{0, NULL, 0, NULL, NULL}
};
+const EnumPropertyItem rna_enum_collection_type_items[] = {
+ {COLLECTION_TYPE_NONE, "NONE", 0, "Normal", ""},
+ {COLLECTION_TYPE_GROUP_INTERNAL, "GROUP_INTERNAL", 0, "Group Internal", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
#ifdef RNA_RUNTIME
+#include "DNA_group_types.h"
#include "DNA_object_types.h"
#include "RNA_access.h"
@@ -69,6 +76,20 @@ const EnumPropertyItem rna_enum_layer_collection_mode_settings_type_items[] = {
#include "DEG_depsgraph_build.h"
#include "DEG_depsgraph_query.h"
+static StructRNA *rna_SceneCollection_refine(PointerRNA *ptr)
+{
+ SceneCollection *scene_collection = (SceneCollection *)ptr->data;
+ switch (scene_collection->type) {
+ case COLLECTION_TYPE_GROUP_INTERNAL:
+ case COLLECTION_TYPE_NONE:
+ return &RNA_SceneCollection;
+ default:
+ BLI_assert(!"Collection type not fully implemented");
+ break;
+ }
+ return &RNA_SceneCollection;
+}
+
static void rna_SceneCollection_name_set(PointerRNA *ptr, const char *value)
{
Scene *scene = (Scene *)ptr->id.data;
@@ -96,9 +117,7 @@ static PointerRNA rna_SceneCollection_objects_get(CollectionPropertyIterator *it
static int rna_SceneCollection_move_above(ID *id, SceneCollection *sc_src, Main *bmain, SceneCollection *sc_dst)
{
- Scene *scene = (Scene *)id;
-
- if (!BKE_collection_move_above(scene, sc_dst, sc_src)) {
+ if (!BKE_collection_move_above(id, sc_dst, sc_src)) {
return 0;
}
@@ -110,9 +129,7 @@ static int rna_SceneCollection_move_above(ID *id, SceneCollection *sc_src, Main
static int rna_SceneCollection_move_below(ID *id, SceneCollection *sc_src, Main *bmain, SceneCollection *sc_dst)
{
- Scene *scene = (Scene *)id;
-
- if (!BKE_collection_move_below(scene, sc_dst, sc_src)) {
+ if (!BKE_collection_move_below(id, sc_dst, sc_src)) {
return 0;
}
@@ -124,9 +141,7 @@ static int rna_SceneCollection_move_below(ID *id, SceneCollection *sc_src, Main
static int rna_SceneCollection_move_into(ID *id, SceneCollection *sc_src, Main *bmain, SceneCollection *sc_dst)
{
- Scene *scene = (Scene *)id;
-
- if (!BKE_collection_move_into(scene, sc_dst, sc_src)) {
+ if (!BKE_collection_move_into(id, sc_dst, sc_src)) {
return 0;
}
@@ -139,8 +154,7 @@ static int rna_SceneCollection_move_into(ID *id, SceneCollection *sc_src, Main *
static SceneCollection *rna_SceneCollection_new(
ID *id, SceneCollection *sc_parent, Main *bmain, const char *name)
{
- Scene *scene = (Scene *)id;
- SceneCollection *sc = BKE_collection_add(scene, sc_parent, name);
+ SceneCollection *sc = BKE_collection_add(id, sc_parent, COLLECTION_TYPE_NONE, name);
DEG_relations_tag_update(bmain);
WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
@@ -151,7 +165,6 @@ static SceneCollection *rna_SceneCollection_new(
static void rna_SceneCollection_remove(
ID *id, SceneCollection *sc_parent, Main *bmain, ReportList *reports, PointerRNA *sc_ptr)
{
- Scene *scene = (Scene *)id;
SceneCollection *sc = sc_ptr->data;
const int index = BLI_findindex(&sc_parent->scene_collections, sc);
@@ -161,7 +174,7 @@ static void rna_SceneCollection_remove(
return;
}
- if (!BKE_collection_remove(scene, sc)) {
+ if (!BKE_collection_remove(id, sc)) {
BKE_reportf(reports, RPT_ERROR, "Collection '%s' could not be removed from collection '%s'",
sc->name, sc_parent->name);
return;
@@ -203,7 +216,7 @@ void rna_SceneCollection_object_link(
return;
}
- BKE_collection_object_add(scene, sc, ob);
+ BKE_collection_object_add(&scene->id, sc, ob);
/* TODO(sergey): Only update relations for the current scene. */
DEG_relations_tag_update(bmain);
@@ -226,7 +239,7 @@ static void rna_SceneCollection_object_unlink(
return;
}
- BKE_collection_object_remove(bmain, scene, sc, ob, false);
+ BKE_collection_object_remove(bmain, &scene->id, sc, ob, false);
/* needed otherwise the depgraph will contain freed objects which can crash, see [#20958] */
DEG_relations_tag_update(bmain);
@@ -386,6 +399,7 @@ RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(shadow_high_bitdepth)
RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(taa_samples)
RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(gi_diffuse_bounces)
RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(gi_cubemap_resolution)
+RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(gi_visibility_resolution)
/* object engine */
RNA_LAYER_MODE_OBJECT_GET_SET_BOOL(show_wire)
@@ -417,11 +431,17 @@ static void rna_ViewLayerEngineSettings_update(bContext *C, PointerRNA *UNUSED(p
DEG_id_tag_update(&scene->id, 0);
}
-static void rna_LayerCollectionEngineSettings_update(bContext *C, PointerRNA *UNUSED(ptr))
+static void rna_LayerCollectionEngineSettings_update(bContext *UNUSED(C), PointerRNA *ptr)
{
- Scene *scene = CTX_data_scene(C);
+ ID *id = ptr->id.data;
/* TODO(sergey): Use proper flag for tagging here. */
- DEG_id_tag_update(&scene->id, 0);
+ DEG_id_tag_update(id, 0);
+
+ /* Instead of passing 'noteflag' to the rna update function, we handle the notifier ourselves.
+ * We need to do this because the LayerCollection may be coming from different ID types (Scene or Group)
+ * and when using NC_SCENE the id most match the active scene for the listener to receive the notification.*/
+
+ WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL);
}
static void rna_LayerCollectionEngineSettings_wire_update(bContext *C, PointerRNA *UNUSED(ptr))
@@ -641,9 +661,7 @@ static PointerRNA rna_LayerCollection_objects_get(CollectionPropertyIterator *it
static int rna_LayerCollection_move_above(ID *id, LayerCollection *lc_src, Main *bmain, LayerCollection *lc_dst)
{
- Scene *scene = (Scene *)id;
-
- if (!BKE_layer_collection_move_above(scene, lc_dst, lc_src)) {
+ if (!BKE_layer_collection_move_above(id, lc_dst, lc_src)) {
return 0;
}
@@ -655,9 +673,7 @@ static int rna_LayerCollection_move_above(ID *id, LayerCollection *lc_src, Main
static int rna_LayerCollection_move_below(ID *id, LayerCollection *lc_src, Main *bmain, LayerCollection *lc_dst)
{
- Scene *scene = (Scene *)id;
-
- if (!BKE_layer_collection_move_below(scene, lc_dst, lc_src)) {
+ if (!BKE_layer_collection_move_below(id, lc_dst, lc_src)) {
return 0;
}
@@ -669,9 +685,7 @@ static int rna_LayerCollection_move_below(ID *id, LayerCollection *lc_src, Main
static int rna_LayerCollection_move_into(ID *id, LayerCollection *lc_src, Main *bmain, LayerCollection *lc_dst)
{
- Scene *scene = (Scene *)id;
-
- if (!BKE_layer_collection_move_into(scene, lc_dst, lc_src)) {
+ if (!BKE_layer_collection_move_into(id, lc_dst, lc_src)) {
return 0;
}
@@ -681,19 +695,27 @@ static int rna_LayerCollection_move_into(ID *id, LayerCollection *lc_src, Main *
return 1;
}
-static void rna_LayerCollection_flag_update(bContext *C, PointerRNA *UNUSED(ptr))
+static void rna_LayerCollection_flag_update(bContext *C, PointerRNA *ptr)
{
- Scene *scene = CTX_data_scene(C);
+ ID *id = ptr->id.data;
/* TODO(sergey): Use proper flag for tagging here. */
- DEG_id_tag_update(&scene->id, 0);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ DEG_id_tag_update(id, 0);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
}
static void rna_LayerCollection_enable_set(
ID *id, LayerCollection *layer_collection, Main *bmain, bContext *C, ReportList *reports, int value)
{
- Scene *scene = (Scene *)id;
- ViewLayer *view_layer = BKE_view_layer_find_from_collection(scene, layer_collection);
+ ViewLayer *view_layer;
+ if (GS(id->name) == ID_SCE) {
+ Scene *scene = (Scene *)id;
+ view_layer = BKE_view_layer_find_from_collection(&scene->id, layer_collection);
+ }
+ else {
+ BLI_assert(GS(id->name) == ID_GR);
+ Group *group = (Group *)id;
+ view_layer = group->view_layer;
+ }
if (layer_collection->flag & COLLECTION_DISABLED) {
if (value == 1) {
@@ -715,6 +737,7 @@ static void rna_LayerCollection_enable_set(
}
}
+ Scene *scene = CTX_data_scene(C);
DEG_relations_tag_update(bmain);
/* TODO(sergey): Use proper flag for tagging here. */
DEG_id_tag_update(&scene->id, 0);
@@ -722,6 +745,32 @@ static void rna_LayerCollection_enable_set(
WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
}
+static Group *rna_LayerCollection_create_group(
+ ID *id, LayerCollection *layer_collection, Main *bmain, bContext *C, ReportList *reports)
+{
+ Group *group;
+ Scene *scene = (Scene *)id;
+ SceneCollection *scene_collection = layer_collection->scene_collection;
+
+ /* The master collection can't be converted. */
+ if (scene_collection == BKE_collection_master(&scene->id)) {
+ BKE_report(reports, RPT_ERROR, "The master collection can't be converted to group");
+ return NULL;
+ }
+
+ group = BKE_collection_group_create(bmain, scene, layer_collection);
+ if (group == NULL) {
+ BKE_reportf(reports, RPT_ERROR, "Failed to convert collection %s", scene_collection->name);
+ return NULL;
+ }
+
+ DEG_relations_tag_update(bmain);
+ /* TODO(sergey): Use proper flag for tagging here. */
+ DEG_id_tag_update(&scene->id, 0);
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
+ return group;
+}
+
static int rna_LayerCollections_active_collection_index_get(PointerRNA *ptr)
{
ViewLayer *view_layer = (ViewLayer *)ptr->data;
@@ -863,7 +912,7 @@ static void rna_LayerObjects_selected_begin(CollectionPropertyIterator *iter, Po
static void rna_ViewLayer_update_tagged(ViewLayer *UNUSED(view_layer), bContext *C)
{
Depsgraph *graph = CTX_data_depsgraph(C);
- DEG_OBJECT_ITER(graph, ob, DEG_OBJECT_ITER_FLAG_ALL)
+ DEG_OBJECT_ITER(graph, ob, DEG_ITER_OBJECT_FLAG_ALL)
{
/* Don't do anything, we just need to run the iterator to flush
* the base info to the objects. */
@@ -1034,6 +1083,7 @@ static void rna_def_scene_collection(BlenderRNA *brna)
srna = RNA_def_struct(brna, "SceneCollection", NULL);
RNA_def_struct_ui_text(srna, "Scene Collection", "Collection");
+ RNA_def_struct_refine_func(srna, "rna_SceneCollection_refine");
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SceneCollection_name_set");
@@ -1041,6 +1091,11 @@ static void rna_def_scene_collection(BlenderRNA *brna)
RNA_def_struct_name_property(srna, prop);
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, NULL);
+ prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_collection_type_items);
+ RNA_def_property_ui_text(prop, "Type", "Type of collection");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
prop = RNA_def_property(srna, "filter", PROP_STRING, PROP_NONE);
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SceneCollection_filter_set");
RNA_def_property_ui_text(prop, "Filter", "Filter to dynamically include objects based on their names (e.g., CHAR_*)");
@@ -1152,6 +1207,14 @@ static void rna_def_view_layer_engine_settings_eevee(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+ static const EnumPropertyItem eevee_gi_visibility_size_items[] = {
+ {8, "8", 0, "8px", ""},
+ {16, "16", 0, "16px", ""},
+ {32, "32", 0, "32px", ""},
+ {64, "64", 0, "64px", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
static const EnumPropertyItem eevee_volumetric_tile_size_items[] = {
{2, "2", 0, "2px", ""},
{4, "4", 0, "4px", ""},
@@ -1178,12 +1241,22 @@ static void rna_def_view_layer_engine_settings_eevee(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_ViewLayerEngineSettings_update");
prop = RNA_def_property(srna, "gi_cubemap_resolution", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_funcs(prop, "rna_LayerEngineSettings_Eevee_gi_cubemap_resolution_get", "rna_LayerEngineSettings_Eevee_gi_cubemap_resolution_set", NULL);
+ RNA_def_property_enum_funcs(prop, "rna_LayerEngineSettings_Eevee_gi_cubemap_resolution_get",
+ "rna_LayerEngineSettings_Eevee_gi_cubemap_resolution_set", NULL);
RNA_def_property_enum_items(prop, eevee_shadow_size_items);
RNA_def_property_ui_text(prop, "Cubemap Size", "Size of every cubemaps");
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_ViewLayerEngineSettings_update");
+ prop = RNA_def_property(srna, "gi_visibility_resolution", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_funcs(prop, "rna_LayerEngineSettings_Eevee_gi_visibility_resolution_get",
+ "rna_LayerEngineSettings_Eevee_gi_visibility_resolution_set", NULL);
+ RNA_def_property_enum_items(prop, eevee_gi_visibility_size_items);
+ RNA_def_property_ui_text(prop, "Irradiance Visibility Size",
+ "Size of the shadow map applied to each irradiance sample");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
+ RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_ViewLayerEngineSettings_update");
+
/* Temporal Anti-Aliasing (super sampling) */
prop = RNA_def_property(srna, "taa_samples", PROP_INT, PROP_NONE);
RNA_def_property_int_funcs(prop, "rna_LayerEngineSettings_Eevee_taa_samples_get",
@@ -1420,14 +1493,14 @@ static void rna_def_view_layer_engine_settings_eevee(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1f, 2);
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+ RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update");
prop = RNA_def_property(srna, "gtao_quality", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Eevee_gtao_quality_get", "rna_LayerEngineSettings_Eevee_gtao_quality_set", NULL);
RNA_def_property_ui_text(prop, "Trace Quality", "Quality of the horizon search");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+ RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update");
prop = RNA_def_property(srna, "gtao_distance", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Eevee_gtao_distance_get", "rna_LayerEngineSettings_Eevee_gtao_distance_set", NULL);
@@ -1435,7 +1508,7 @@ static void rna_def_view_layer_engine_settings_eevee(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0f, 100000.0f);
RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, 3);
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+ RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update");
prop = RNA_def_property(srna, "gtao_samples", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_funcs(prop, "rna_LayerEngineSettings_Eevee_gtao_samples_get",
@@ -1624,49 +1697,49 @@ static void rna_def_layer_collection_engine_settings_clay(BlenderRNA *brna)
RNA_def_property_enum_items(prop, clay_matcap_items);
RNA_def_property_ui_text(prop, "Matcap", "Image to use for Material Capture by this material");
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+ RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update");
prop = RNA_def_property(srna, "matcap_rotation", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_matcap_rotation_get", "rna_LayerEngineSettings_Clay_matcap_rotation_set", NULL);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Matcap Rotation", "Orientation of the matcap on the model");
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+ RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update");
prop = RNA_def_property(srna, "matcap_hue", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_matcap_hue_get", "rna_LayerEngineSettings_Clay_matcap_hue_set", NULL);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Matcap Hue Shift", "Hue correction of the matcap");
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+ RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update");
prop = RNA_def_property(srna, "matcap_saturation", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_matcap_saturation_get", "rna_LayerEngineSettings_Clay_matcap_saturation_set", NULL);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Matcap Saturation", "Saturation correction of the matcap");
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+ RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update");
prop = RNA_def_property(srna, "matcap_value", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_matcap_value_get", "rna_LayerEngineSettings_Clay_matcap_value_set", NULL);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Matcap Value", "Value correction of the matcap");
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+ RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update");
prop = RNA_def_property(srna, "ssao_factor_cavity", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_ssao_factor_cavity_get", "rna_LayerEngineSettings_Clay_ssao_factor_cavity_set", NULL);
RNA_def_property_ui_text(prop, "Cavity Strength", "Strength of the Cavity effect");
RNA_def_property_range(prop, 0.0f, 250.0f);
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+ RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update");
prop = RNA_def_property(srna, "ssao_factor_edge", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_ssao_factor_edge_get", "rna_LayerEngineSettings_Clay_ssao_factor_edge_set", NULL);
RNA_def_property_ui_text(prop, "Edge Strength", "Strength of the Edge effect");
RNA_def_property_range(prop, 0.0f, 250.0f);
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+ RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update");
prop = RNA_def_property(srna, "ssao_distance", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_ssao_distance_get", "rna_LayerEngineSettings_Clay_ssao_distance_set", NULL);
@@ -1674,7 +1747,7 @@ static void rna_def_layer_collection_engine_settings_clay(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0f, 100000.0f);
RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, 3);
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+ RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update");
prop = RNA_def_property(srna, "ssao_attenuation", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_ssao_attenuation_get", "rna_LayerEngineSettings_Clay_ssao_attenuation_set", NULL);
@@ -1682,14 +1755,14 @@ static void rna_def_layer_collection_engine_settings_clay(BlenderRNA *brna)
RNA_def_property_range(prop, 1.0f, 100000.0f);
RNA_def_property_ui_range(prop, 1.0f, 100.0f, 1, 3);
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+ RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update");
prop = RNA_def_property(srna, "hair_brightness_randomness", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Clay_hair_brightness_randomness_get", "rna_LayerEngineSettings_Clay_hair_brightness_randomness_set", NULL);
RNA_def_property_ui_text(prop, "Hair Brightness Randomness", "Brightness randomness for hair");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+ RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update");
RNA_define_verify_sdna(1); /* not in sdna */
}
@@ -1710,13 +1783,13 @@ static void rna_def_layer_collection_mode_settings_object(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Wire", "Add the object's wireframe over solid drawing");
RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_ObjectMode_show_wire_get", "rna_LayerEngineSettings_ObjectMode_show_wire_set");
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+ RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update");
prop = RNA_def_property(srna, "show_backface_culling", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_ui_text(prop, "Backface Culling", "");
RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_ObjectMode_show_backface_culling_get", "rna_LayerEngineSettings_ObjectMode_show_backface_culling_set");
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+ RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update");
RNA_define_verify_sdna(1); /* not in sdna */
}
@@ -1736,31 +1809,31 @@ static void rna_def_layer_collection_mode_settings_edit(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Hidden Wire", "Use hidden wireframe display");
RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_EditMode_show_occlude_wire_get", "rna_LayerEngineSettings_EditMode_show_occlude_wire_set");
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+ RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update");
prop = RNA_def_property(srna, "show_weight", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_ui_text(prop, "Show Weights", "Draw weights in editmode");
RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_EditMode_show_weight_get", "rna_LayerEngineSettings_EditMode_show_weight_set");
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+ RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update");
prop = RNA_def_property(srna, "face_normals_show", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_ui_text(prop, "Draw Normals", "Display face normals as lines");
RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_EditMode_face_normals_show_get", "rna_LayerEngineSettings_EditMode_face_normals_show_set");
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+ RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update");
prop = RNA_def_property(srna, "vert_normals_show", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_ui_text(prop, "Draw Vertex Normals", "Display vertex normals as lines");
RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_EditMode_vert_normals_show_get", "rna_LayerEngineSettings_EditMode_vert_normals_show_set");
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+ RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update");
prop = RNA_def_property(srna, "loop_normals_show", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_ui_text(prop, "Draw Split Normals", "Display vertex-per-face normals as lines");
RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_EditMode_loop_normals_show_get", "rna_LayerEngineSettings_EditMode_loop_normals_show_set");
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+ RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update");
prop = RNA_def_property(srna, "normals_length", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_ui_text(prop, "Normal Size", "Display size for normals in the 3D view");
@@ -1768,14 +1841,14 @@ static void rna_def_layer_collection_mode_settings_edit(BlenderRNA *brna)
RNA_def_property_range(prop, 0.00001, 1000.0);
RNA_def_property_ui_range(prop, 0.01, 10.0, 10.0, 2);
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+ RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update");
prop = RNA_def_property(srna, "backwire_opacity", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_ui_text(prop, "Backwire Opacity", "Opacity when rendering transparent wires");
RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_EditMode_backwire_opacity_get", "rna_LayerEngineSettings_EditMode_backwire_opacity_set", NULL);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+ RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update");
RNA_define_verify_sdna(1); /* not in sdna */
}
@@ -1795,7 +1868,7 @@ static void rna_def_layer_collection_mode_settings_paint_weight(BlenderRNA *brna
RNA_def_property_ui_text(prop, "Use Shading", "Whether to use shaded or shadeless drawing");
RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_PaintWeightMode_use_shading_get", "rna_LayerEngineSettings_PaintWeightMode_use_shading_set");
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+ RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update");
prop = RNA_def_property(srna, "use_wire", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_ui_text(prop, "Show Wire", "Whether to overlay wireframe onto the mesh");
@@ -1821,7 +1894,7 @@ static void rna_def_layer_collection_mode_settings_paint_vertex(BlenderRNA *brna
RNA_def_property_ui_text(prop, "Use Shading", "Whether to use shaded or shadeless drawing");
RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_PaintVertexMode_use_shading_get", "rna_LayerEngineSettings_PaintVertexMode_use_shading_set");
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_LayerCollectionEngineSettings_update");
+ RNA_def_property_update(prop, 0, "rna_LayerCollectionEngineSettings_update");
prop = RNA_def_property(srna, "use_wire", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_ui_text(prop, "Show Wire", "Whether to overlay wireframe onto the mesh");
@@ -1997,6 +2070,12 @@ static void rna_def_layer_collection(BlenderRNA *brna)
parm = RNA_def_boolean(func, "value", 1, "Enable", "");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
+ func = RNA_def_function(srna, "create_group", "rna_LayerCollection_create_group");
+ RNA_def_function_ui_description(func, "Enable or disable a collection");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
+ parm = RNA_def_pointer(func, "result", "Group", "", "Newly created Group");
+ RNA_def_function_return(func, parm);
+
/* Flags */
prop = RNA_def_property(srna, "is_enabled", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", COLLECTION_DISABLED);
diff --git a/source/blender/makesrna/intern/rna_lightprobe.c b/source/blender/makesrna/intern/rna_lightprobe.c
index 448d847a959..61dc835022b 100644
--- a/source/blender/makesrna/intern/rna_lightprobe.c
+++ b/source/blender/makesrna/intern/rna_lightprobe.c
@@ -160,6 +160,25 @@ static void rna_def_lightprobe(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Resolution Z", "Number of sample along the z axis of the volume");
RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, "rna_LightProbe_recalc");
+ prop = RNA_def_property(srna, "visibility_buffer_bias", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "vis_bias");
+ RNA_def_property_range(prop, 0.001f, 9999.0f);
+ RNA_def_property_ui_range(prop, 0.001f, 5.0f, 1.0, 3);
+ RNA_def_property_ui_text(prop, "Visibility Bias", "Bias for reducing self shadowing");
+ RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, NULL);
+
+ prop = RNA_def_property(srna, "visibility_bleed_bias", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "vis_bleedbias");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Visibility Bleed Bias", "Bias for reducing light-bleed on variance shadow maps");
+ RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, NULL);
+
+ prop = RNA_def_property(srna, "visibility_blur", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "vis_blur");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Visibility Blur", "Filter size of the visibilty blur");
+ RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING, "rna_LightProbe_recalc");
+
/* Data preview */
prop = RNA_def_property(srna, "show_data", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", LIGHTPROBE_FLAG_SHOW_DATA);
diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c
index d1b28bffc7e..f15006fa0ed 100644
--- a/source/blender/makesrna/intern/rna_main_api.c
+++ b/source/blender/makesrna/intern/rna_main_api.c
@@ -249,7 +249,6 @@ static Object *rna_Main_objects_new(Main *bmain, ReportList *reports, const char
}
ob = BKE_object_add_only_object(bmain, type, safe_name);
- id_us_min(&ob->id);
ob->data = data;
test_object_materials(ob, ob->data);
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index d482f7e1b94..c443b68b209 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -1817,7 +1817,7 @@ static void rna_def_modifier_armature(BlenderRNA *brna)
prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
RNA_def_property_ui_text(prop, "Object", "Armature object to deform with");
RNA_def_property_pointer_funcs(prop, NULL, "rna_ArmatureModifier_object_set", NULL, "rna_Armature_object_poll");
- RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK | PROP_OVERRIDABLE_STATIC);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "use_bone_envelopes", PROP_BOOLEAN, PROP_NONE);
@@ -2997,7 +2997,7 @@ static void rna_def_modifier_bevel(BlenderRNA *brna)
prop = RNA_def_property(srna, "profile", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_range(prop, 0.15f, 1.0f, 0.05, 2);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.05, 2);
RNA_def_property_ui_text(prop, "Profile", "The profile shape (0.5 = round)");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 37957f55f5c..a153590f4ac 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -57,7 +57,6 @@
#include "BLI_sys_types.h" /* needed for intptr_t used in ED_mesh.h */
#include "ED_mesh.h"
-#include "ED_object.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -2423,7 +2422,7 @@ static void rna_def_object(BlenderRNA *brna)
/* parent */
prop = RNA_def_property(srna, "parent", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_funcs(prop, NULL, "rna_Object_parent_set", NULL, NULL);
- RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK | PROP_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Parent", "Parent Object");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_dependency_update");
@@ -2501,6 +2500,7 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "location", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_float_sdna(prop, NULL, "loc");
RNA_def_property_editable_array_func(prop, "rna_Object_location_editable");
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Location", "Location of the object");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update");
@@ -2508,6 +2508,7 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "rotation_quaternion", PROP_FLOAT, PROP_QUATERNION);
RNA_def_property_float_sdna(prop, NULL, "quat");
RNA_def_property_editable_array_func(prop, "rna_Object_rotation_4d_editable");
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
RNA_def_property_float_array_default(prop, default_quat);
RNA_def_property_ui_text(prop, "Quaternion Rotation", "Rotation in Quaternions");
RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update");
@@ -2521,12 +2522,14 @@ static void rna_def_object(BlenderRNA *brna)
"rna_Object_rotation_axis_angle_set", NULL);
RNA_def_property_editable_array_func(prop, "rna_Object_rotation_4d_editable");
RNA_def_property_float_array_default(prop, default_axisAngle);
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Axis-Angle Rotation", "Angle of Rotation for Axis-Angle rotation representation");
RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update");
prop = RNA_def_property(srna, "rotation_euler", PROP_FLOAT, PROP_EULER);
RNA_def_property_float_sdna(prop, NULL, "rot");
RNA_def_property_editable_array_func(prop, "rna_Object_rotation_euler_editable");
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Euler Rotation", "Rotation in Eulers");
RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update");
@@ -2539,7 +2542,7 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "size");
- RNA_def_property_flag(prop, PROP_PROPORTIONAL);
+ RNA_def_property_flag(prop, PROP_PROPORTIONAL | PROP_OVERRIDABLE_STATIC);
RNA_def_property_editable_array_func(prop, "rna_Object_scale_editable");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, 3);
RNA_def_property_float_array_default(prop, default_scale);
@@ -2666,6 +2669,7 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "modifiers", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "Modifier");
RNA_def_property_ui_text(prop, "Modifiers", "Modifiers affecting the geometric data of the object");
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
rna_def_object_modifiers(brna, prop);
/* constraints */
@@ -2978,6 +2982,7 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "pose", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "pose");
RNA_def_property_struct_type(prop, "Pose");
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Pose", "Current pose for armatures");
/* shape keys */
diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c
index b4c721a88b3..baf7f5e6aa3 100644
--- a/source/blender/makesrna/intern/rna_pose.c
+++ b/source/blender/makesrna/intern/rna_pose.c
@@ -839,6 +839,7 @@ static void rna_def_pose_channel(BlenderRNA *brna)
/* Transformation settings */
prop = RNA_def_property(srna, "location", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_float_sdna(prop, NULL, "loc");
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
RNA_def_property_editable_array_func(prop, "rna_PoseChannel_location_editable");
RNA_def_property_ui_text(prop, "Location", "");
RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
@@ -846,7 +847,7 @@ static void rna_def_pose_channel(BlenderRNA *brna)
prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "size");
- RNA_def_property_flag(prop, PROP_PROPORTIONAL);
+ RNA_def_property_flag(prop, PROP_PROPORTIONAL | PROP_OVERRIDABLE_STATIC);
RNA_def_property_editable_array_func(prop, "rna_PoseChannel_scale_editable");
RNA_def_property_float_array_default(prop, default_scale);
RNA_def_property_ui_text(prop, "Scale", "");
@@ -854,6 +855,7 @@ static void rna_def_pose_channel(BlenderRNA *brna)
prop = RNA_def_property(srna, "rotation_quaternion", PROP_FLOAT, PROP_QUATERNION);
RNA_def_property_float_sdna(prop, NULL, "quat");
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
RNA_def_property_editable_array_func(prop, "rna_PoseChannel_rotation_4d_editable");
RNA_def_property_float_array_default(prop, default_quat);
RNA_def_property_ui_text(prop, "Quaternion Rotation", "Rotation in Quaternions");
@@ -863,6 +865,7 @@ static void rna_def_pose_channel(BlenderRNA *brna)
* having a single one is better for Keyframing and other property-management situations...
*/
prop = RNA_def_property(srna, "rotation_axis_angle", PROP_FLOAT, PROP_AXISANGLE);
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
RNA_def_property_array(prop, 4);
RNA_def_property_float_funcs(prop, "rna_PoseChannel_rotation_axis_angle_get",
"rna_PoseChannel_rotation_axis_angle_set", NULL);
@@ -873,6 +876,7 @@ static void rna_def_pose_channel(BlenderRNA *brna)
prop = RNA_def_property(srna, "rotation_euler", PROP_FLOAT, PROP_EULER);
RNA_def_property_float_sdna(prop, NULL, "eul");
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
RNA_def_property_editable_array_func(prop, "rna_PoseChannel_rotation_euler_editable");
RNA_def_property_ui_text(prop, "Euler Rotation", "Rotation in Eulers");
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
@@ -1399,6 +1403,7 @@ static void rna_def_pose(BlenderRNA *brna)
prop = RNA_def_property(srna, "bones", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "chanbase", NULL);
RNA_def_property_struct_type(prop, "PoseBone");
+ RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
RNA_def_property_ui_text(prop, "Pose Bones", "Individual pose bones for the armature");
/* can be removed, only for fast lookup */
RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, NULL, NULL, NULL, "rna_PoseBones_lookup_string", NULL);
diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c
index 507262675b3..24d56ef2a19 100644
--- a/source/blender/makesrna/intern/rna_rna.c
+++ b/source/blender/makesrna/intern/rna_rna.c
@@ -107,6 +107,8 @@ const EnumPropertyItem rna_enum_property_unit_items[] = {
#include "MEM_guardedalloc.h"
#include "BLI_ghash.h"
+#include "BKE_library_override.h"
+
/* Struct */
static void rna_Struct_identifier_get(PointerRNA *ptr, char *value)
@@ -564,6 +566,13 @@ static int rna_Property_animatable_get(PointerRNA *ptr)
return (prop->flag & PROP_ANIMATABLE) != 0;
}
+static int rna_Property_overridable_get(PointerRNA *ptr)
+{
+ PropertyRNA *prop = (PropertyRNA *)ptr->data;
+
+ return (prop->flag & PROP_OVERRIDABLE_STATIC) != 0;
+}
+
static int rna_Property_use_output_get(PointerRNA *ptr)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
@@ -1082,6 +1091,1003 @@ static int rna_BlenderRNA_structs_lookup_string(PointerRNA *ptr, const char *key
return false;
}
+/* Default override (and compare) callbacks. */
+
+/* Used for both Pointer and Collection properties. */
+static int rna_property_override_equals_propptr(
+ PointerRNA *propptr_a, PointerRNA *propptr_b, eRNACompareMode mode,
+ IDOverrideStatic *override, const char *rna_path, bool *r_override_changed, const int flags)
+{
+ bool is_id = false;
+ bool is_type_null = false;
+
+ /* Beware, PointerRNA_NULL has no type and is considered a 'blank page'! */
+ if (propptr_a->type == NULL) {
+ if (propptr_b->type == NULL) {
+ if (r_override_changed) {
+ *r_override_changed = false;
+ }
+ return 0;
+ }
+ is_id = RNA_struct_is_ID(propptr_b->type);
+ is_type_null = true;
+ }
+ else {
+ is_id = RNA_struct_is_ID(propptr_a->type);
+ is_type_null = (propptr_b->type == NULL);
+ }
+
+ if (is_id) {
+ BLI_assert(propptr_a->data == propptr_a->id.data && propptr_b->data == propptr_b->id.data);
+ }
+
+ if (override) {
+ if (rna_path) {
+ if (is_type_null || is_id) {
+ /* In case this is an ID (or one of the pointers is NULL), do not compare structs!
+ * This is a quite safe path to infinite loop.
+ * Instead, just compare pointers themselves (we assume sub-ID structs cannot loop). */
+ const int comp = (propptr_a->data != propptr_b->data);
+
+ if (comp != 0 && rna_path) {
+ bool created = false;
+ IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
+
+ if (op != NULL && created) { /* If not yet overridden... */
+ BKE_override_static_property_operation_get(
+ op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL);
+ if (r_override_changed) {
+ *r_override_changed = created;
+ }
+ }
+ }
+
+ return comp;
+ }
+ else {
+ const bool changed = RNA_struct_auto_override(propptr_a, propptr_b, override, rna_path);
+ if (r_override_changed) {
+ *r_override_changed = *r_override_changed || changed;
+ }
+ /* XXX Simplification here, if no override was added we assume they are equal,
+ * this may not be good behavior, time will say. */
+ return !changed;
+ }
+ }
+ else {
+ return !RNA_struct_override_matches(
+ propptr_a, propptr_b, override,
+ flags & RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE,
+ flags & RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN);
+ }
+ }
+ else {
+ return !RNA_struct_equals(propptr_a, propptr_b, mode);
+ }
+}
+
+static char *rna_path_collection_prop_item_extend(const char *rna_path_prop, const char *item_name)
+{
+ const size_t esc_item_name_len = strlen(item_name) * 2;
+ char *esc_item_name = alloca(sizeof(*esc_item_name) * esc_item_name_len);
+ BLI_strescape(esc_item_name, item_name, esc_item_name_len);
+ return BLI_sprintfN("%s[\"%s\"]", rna_path_prop, esc_item_name);
+}
+
+int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b,
+ PropertyRNA *prop_a, PropertyRNA *prop_b,
+ const int len_a, const int len_b,
+ const int mode,
+ IDOverrideStatic *override, const char *rna_path,
+ const int flags, bool *r_override_changed)
+{
+ BLI_assert(len_a == len_b);
+
+ switch (RNA_property_type(prop_a)) {
+ case PROP_BOOLEAN:
+ {
+ if (len_a) {
+ int array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY];
+ int *array_a, *array_b;
+
+ array_a = (len_a > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(int) * len_a, "RNA equals") : array_stack_a;
+ array_b = (len_b > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(int) * len_b, "RNA equals") : array_stack_b;
+
+ RNA_property_boolean_get_array(ptr_a, prop_a, array_a);
+ RNA_property_boolean_get_array(ptr_b, prop_b, array_b);
+
+ const int comp = memcmp(array_a, array_b, sizeof(int) * len_a);
+
+ if (comp != 0 && rna_path) {
+ /* XXX TODO this will have to be refined to handle array items */
+ bool created = false;
+ IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
+
+ if (op != NULL && created) {
+ BKE_override_static_property_operation_get(
+ op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL);
+ if (r_override_changed) {
+ *r_override_changed = created;
+ }
+ }
+ else {
+ /* Already overriden prop, we'll have to check arrays items etc. */
+ }
+ }
+
+ if (array_a != array_stack_a) MEM_freeN(array_a);
+ if (array_b != array_stack_b) MEM_freeN(array_b);
+
+ return comp;
+ }
+ else {
+ const int value_a = RNA_property_boolean_get(ptr_a, prop_a);
+ const int value_b = RNA_property_boolean_get(ptr_b, prop_b);
+ const int comp = (value_a < value_b) ? -1 : (value_a > value_b) ? 1 : 0;
+
+ if (comp != 0 && rna_path) {
+ bool created = false;
+ IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
+
+ if (op != NULL && created) { /* If not yet overridden... */
+ BKE_override_static_property_operation_get(
+ op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL);
+ if (r_override_changed) {
+ *r_override_changed = created;
+ }
+ }
+ }
+
+ return comp;
+ }
+ }
+
+ case PROP_INT:
+ {
+ if (len_a) {
+ int array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY];
+ int *array_a, *array_b;
+
+ array_a = (len_a > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(int) * len_a, "RNA equals") : array_stack_a;
+ array_b = (len_b > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(int) * len_b, "RNA equals") : array_stack_b;
+
+ RNA_property_int_get_array(ptr_a, prop_a, array_a);
+ RNA_property_int_get_array(ptr_b, prop_b, array_b);
+
+ const int comp = memcmp(array_a, array_b, sizeof(int) * len_a);
+
+ if (comp != 0 && rna_path) {
+ /* XXX TODO this will have to be refined to handle array items */
+ bool created = false;
+ IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
+
+ if (op != NULL && created) {
+ BKE_override_static_property_operation_get(
+ op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL);
+ if (r_override_changed) {
+ *r_override_changed = created;
+ }
+ }
+ else {
+ /* Already overriden prop, we'll have to check arrays items etc. */
+ }
+ }
+
+ if (array_a != array_stack_a) MEM_freeN(array_a);
+ if (array_b != array_stack_b) MEM_freeN(array_b);
+
+ return comp;
+ }
+ else {
+ const int value_a = RNA_property_int_get(ptr_a, prop_a);
+ const int value_b = RNA_property_int_get(ptr_b, prop_b);
+ const int comp = (value_a < value_b) ? -1 : (value_a > value_b) ? 1 : 0;
+
+ if (comp != 0 && rna_path) {
+ bool created = false;
+ IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
+
+ if (op != NULL && created) { /* If not yet overridden... */
+ BKE_override_static_property_operation_get(
+ op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL);
+ if (r_override_changed) {
+ *r_override_changed = created;
+ }
+ }
+ }
+
+ return comp;
+ }
+ }
+
+ case PROP_FLOAT:
+ {
+ const bool is_proportional = (prop_a->flag & PROP_PROPORTIONAL) != 0;
+ if (len_a) {
+ float array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY];
+ float *array_a, *array_b;
+
+ array_a = (len_a > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(float) * len_a, "RNA equals") : array_stack_a;
+ array_b = (len_b > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(float) * len_b, "RNA equals") : array_stack_b;
+
+ RNA_property_float_get_array(ptr_a, prop_a, array_a);
+ RNA_property_float_get_array(ptr_b, prop_b, array_b);
+
+ const int comp = memcmp(array_a, array_b, sizeof(float) * len_a);
+
+ if (comp != 0 && rna_path) {
+ /* XXX TODO this will have to be refined to handle array items */
+ bool created = false;
+ IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
+
+ if (op != NULL && created) {
+ BKE_override_static_property_operation_get(
+ op, is_proportional ? IDOVERRIDESTATIC_OP_MULTIPLY : IDOVERRIDESTATIC_OP_REPLACE,
+ NULL, NULL, -1, -1, true, NULL, NULL);
+ if (r_override_changed) {
+ *r_override_changed = created;
+ }
+ }
+ else {
+ /* Already overriden prop, we'll have to check arrays items etc. */
+ }
+ }
+
+ if (array_a != array_stack_a) MEM_freeN(array_a);
+ if (array_b != array_stack_b) MEM_freeN(array_b);
+
+ return comp;
+ }
+ else {
+ const float value_a = RNA_property_float_get(ptr_a, prop_a);
+ const float value_b = RNA_property_float_get(ptr_b, prop_b);
+ const int comp = (value_a < value_b) ? -1 : (value_a > value_b) ? 1 : 0;
+
+ if (comp != 0 && rna_path) {
+ bool created = false;
+ IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
+
+ if (op != NULL && created) { /* If not yet overridden... */
+ BKE_override_static_property_operation_get(
+ op, is_proportional ? IDOVERRIDESTATIC_OP_MULTIPLY : IDOVERRIDESTATIC_OP_REPLACE,
+ NULL, NULL, -1, -1, true, NULL, NULL);
+ if (r_override_changed) {
+ *r_override_changed = created;
+ }
+ }
+ }
+
+ return comp ;
+ }
+ }
+
+ case PROP_ENUM:
+ {
+ const int value_a = RNA_property_enum_get(ptr_a, prop_a);
+ const int value_b = RNA_property_enum_get(ptr_b, prop_b);
+ const int comp = value_a != value_b;
+
+ if (comp != 0 && rna_path) {
+ bool created = false;
+ IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
+
+ if (op != NULL && created) { /* If not yet overridden... */
+ BKE_override_static_property_operation_get(
+ op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL);
+ if (r_override_changed) {
+ *r_override_changed = created;
+ }
+ }
+ }
+
+ return comp;
+ }
+
+ case PROP_STRING:
+ {
+ char fixed_a[128], fixed_b[128];
+ int len_str_a, len_str_b;
+ char *value_a = RNA_property_string_get_alloc(ptr_a, prop_a, fixed_a, sizeof(fixed_a), &len_str_a);
+ char *value_b = RNA_property_string_get_alloc(ptr_b, prop_b, fixed_b, sizeof(fixed_b), &len_str_b);
+ const int comp = strcmp(value_a, value_b);
+
+ if (comp != 0 && rna_path) {
+ bool created = false;
+ IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
+
+ if (op != NULL && created) { /* If not yet overridden... */
+ BKE_override_static_property_operation_get(
+ op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL);
+ if (r_override_changed) {
+ *r_override_changed = created;
+ }
+ }
+ }
+
+ if (value_a != fixed_a) MEM_freeN(value_a);
+ if (value_b != fixed_b) MEM_freeN(value_b);
+
+ return comp;
+ }
+
+ case PROP_POINTER:
+ {
+ if (STREQ(RNA_property_identifier(prop_a), "rna_type")) {
+ /* Dummy 'pass' answer, this is a meta-data and must be ignored... */
+ return 0;
+ }
+ else {
+ PointerRNA propptr_a = RNA_property_pointer_get(ptr_a, prop_a);
+ PointerRNA propptr_b = RNA_property_pointer_get(ptr_b, prop_b);
+ return rna_property_override_equals_propptr(
+ &propptr_a, &propptr_b, mode,
+ override, rna_path, r_override_changed, flags);
+ }
+ break;
+ }
+
+ case PROP_COLLECTION:
+ {
+ bool equals = true;
+ int idx = 0;
+
+ CollectionPropertyIterator iter_a, iter_b;
+ RNA_property_collection_begin(ptr_a, prop_a, &iter_a);
+ RNA_property_collection_begin(ptr_b, prop_b, &iter_b);
+
+ for (; iter_a.valid && iter_b.valid;
+ RNA_property_collection_next(&iter_a), RNA_property_collection_next(&iter_b), idx++)
+ {
+ char *extended_rna_path = NULL;
+
+ if (iter_a.ptr.type != iter_b.ptr.type) {
+ /* nothing we can do (for until we support adding/removing from collections), skip it. */
+ equals = false;
+ continue;
+ }
+
+ PropertyRNA *propname = RNA_struct_name_property(iter_a.ptr.type);
+ char propname_buff_a[256], propname_buff_b[256];
+ char *propname_a = NULL, *propname_b = NULL;
+
+ if (propname != NULL) {
+ propname_a = RNA_property_string_get_alloc(&iter_a.ptr, propname, propname_buff_a, sizeof(propname_buff_a), NULL);
+ propname_b = RNA_property_string_get_alloc(&iter_b.ptr, propname, propname_buff_b, sizeof(propname_buff_b), NULL);
+ if (!STREQ(propname_a, propname_b)) {
+ /* Same as above, not same structs. */
+ equals = false;
+ }
+ else if (rna_path) {
+ extended_rna_path = rna_path_collection_prop_item_extend(rna_path, propname_a);
+ }
+ }
+ else { /* Based on index... */
+ if (rna_path) {
+ extended_rna_path = BLI_sprintfN("%s[%d]", rna_path, idx);
+ }
+ }
+
+ if (equals) {
+ const int eq = rna_property_override_equals_propptr(
+ &iter_a.ptr, &iter_b.ptr, mode,
+ override, extended_rna_path, r_override_changed, flags);
+ equals = equals && eq;
+ }
+
+ if (propname_a != propname_buff_a) {
+ MEM_freeN(propname_a);
+ }
+ if (propname_b != propname_buff_b) {
+ MEM_freeN(propname_b);
+ }
+ MEM_SAFE_FREE(extended_rna_path);
+
+ if (!rna_path && !equals) {
+ break; /* Early out in case we do not want to loop over whole collection. */
+ }
+ }
+
+ equals = equals && !(iter_a.valid || iter_b.valid); /* Not same number of items in both collections... */
+ RNA_property_collection_end(&iter_a);
+ RNA_property_collection_end(&iter_b);
+
+ return (equals == false);
+ }
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+bool rna_property_override_store_default(
+ PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage,
+ PropertyRNA *prop_local, PropertyRNA *prop_reference, PropertyRNA *prop_storage,
+ const int len_local, const int len_reference, const int len_storage,
+ IDOverrideStaticPropertyOperation *opop)
+{
+ BLI_assert(len_local == len_reference && (!ptr_storage || len_local == len_storage));
+ UNUSED_VARS_NDEBUG(len_reference, len_storage);
+
+ bool changed = false;
+ const int index = opop->subitem_reference_index;
+
+ if (!ELEM(opop->operation, IDOVERRIDESTATIC_OP_ADD, IDOVERRIDESTATIC_OP_SUBTRACT, IDOVERRIDESTATIC_OP_MULTIPLY)) {
+ return changed;
+ }
+
+ /* XXX TODO About range limits.
+ * Ideally, it woudl be great to get rid of RNA range in that specific case.
+ * However, this won't be that easy and will add yet another layer of complexity in generated code,
+ * not to mention that we could most likely *not* bypass custom setters anyway.
+ * So for now, if needed second operand value is not in valid range, we simply fall back
+ * to a mere REPLACE operation.
+ * Time will say whether this is acceptable limitation or not. */
+ switch (RNA_property_type(prop_local)) {
+ case PROP_BOOLEAN:
+ /* TODO support boolean ops? Really doubt this would ever be useful though... */
+ BLI_assert(0 && "Boolean properties support no override diff operation");
+ break;
+ case PROP_INT:
+ {
+ int prop_min, prop_max;
+ RNA_property_int_range(ptr_local, prop_local, &prop_min, &prop_max);
+
+ if (len_local) {
+ if (index == -1) {
+ int array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY];
+ int *array_a, *array_b;
+
+ array_a = (len_local > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_a) * len_local, __func__) : array_stack_a;
+ RNA_property_int_get_array(ptr_reference, prop_reference, array_a);
+
+ switch (opop->operation) {
+ case IDOVERRIDESTATIC_OP_ADD:
+ case IDOVERRIDESTATIC_OP_SUBTRACT:
+ {
+ const int fac = opop->operation == IDOVERRIDESTATIC_OP_ADD ? 1 : -1;
+ const int other_op = opop->operation == IDOVERRIDESTATIC_OP_ADD ? IDOVERRIDESTATIC_OP_SUBTRACT : IDOVERRIDESTATIC_OP_ADD;
+ bool do_set = true;
+ array_b = (len_local > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_b) * len_local, __func__) : array_stack_b;
+ RNA_property_int_get_array(ptr_local, prop_local, array_b);
+ for (int i = len_local; i--;) {
+ array_b[i] = fac * (array_b[i] - array_a[i]);
+ if (array_b[i] < prop_min || array_b[i] > prop_max) {
+ opop->operation = other_op;
+ for (int j = len_local; j--;) {
+ array_b[j] = j >= i ? -array_b[j] : fac * (array_a[j] - array_b[j]);
+ if (array_b[j] < prop_min || array_b[j] > prop_max) {
+ /* We failed to find a suitable diff op,
+ * fall back to plain REPLACE one. */
+ opop->operation = IDOVERRIDESTATIC_OP_REPLACE;
+ do_set = false;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ if (do_set) {
+ changed = true;
+ RNA_property_int_set_array(ptr_storage, prop_storage, array_b);
+ }
+ if (array_b != array_stack_b) MEM_freeN(array_b);
+ break;
+ }
+ default:
+ BLI_assert(0 && "Unsupported RNA override diff operation on integer");
+ break;
+ }
+
+ if (array_a != array_stack_a) MEM_freeN(array_a);
+ }
+ else {
+ const int value = RNA_property_int_get_index(ptr_reference, prop_reference, index);
+
+ switch (opop->operation) {
+ case IDOVERRIDESTATIC_OP_ADD:
+ case IDOVERRIDESTATIC_OP_SUBTRACT:
+ {
+ const int fac = opop->operation == IDOVERRIDESTATIC_OP_ADD ? 1 : -1;
+ const int other_op = opop->operation == IDOVERRIDESTATIC_OP_ADD ? IDOVERRIDESTATIC_OP_SUBTRACT : IDOVERRIDESTATIC_OP_ADD;
+ int b = fac * (RNA_property_int_get_index(ptr_local, prop_local, index) - value);
+ if (b < prop_min || b > prop_max) {
+ opop->operation = other_op;
+ b = -b;
+ if (b < prop_min || b > prop_max) {
+ opop->operation = IDOVERRIDESTATIC_OP_REPLACE;
+ break;
+ }
+ }
+ changed = true;
+ RNA_property_int_set_index(ptr_storage, prop_storage, index, b);
+ break;
+ }
+ default:
+ BLI_assert(0 && "Unsupported RNA override diff operation on integer");
+ break;
+ }
+ }
+ }
+ else {
+ const int value = RNA_property_int_get(ptr_reference, prop_reference);
+
+ switch (opop->operation) {
+ case IDOVERRIDESTATIC_OP_ADD:
+ case IDOVERRIDESTATIC_OP_SUBTRACT:
+ {
+ const int fac = opop->operation == IDOVERRIDESTATIC_OP_ADD ? 1 : -1;
+ const int other_op = opop->operation == IDOVERRIDESTATIC_OP_ADD ? IDOVERRIDESTATIC_OP_SUBTRACT : IDOVERRIDESTATIC_OP_ADD;
+ int b = fac * (RNA_property_int_get(ptr_local, prop_local) - value);
+ if (b < prop_min || b > prop_max) {
+ opop->operation = other_op;
+ b = -b;
+ if (b < prop_min || b > prop_max) {
+ opop->operation = IDOVERRIDESTATIC_OP_REPLACE;
+ break;
+ }
+ }
+ changed = true;
+ RNA_property_int_set(ptr_storage, prop_storage, b);
+ break;
+ }
+ default:
+ BLI_assert(0 && "Unsupported RNA override diff operation on integer");
+ break;
+ }
+ }
+ break;
+ }
+ case PROP_FLOAT:
+ {
+ float prop_min, prop_max;
+ RNA_property_float_range(ptr_local, prop_local, &prop_min, &prop_max);
+
+ if (len_local) {
+ if (index == -1) {
+ float array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY];
+ float *array_a, *array_b;
+
+ array_a = (len_local > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_a) * len_local, __func__) : array_stack_a;
+
+ RNA_property_float_get_array(ptr_reference, prop_reference, array_a);
+ switch (opop->operation) {
+ case IDOVERRIDESTATIC_OP_ADD:
+ case IDOVERRIDESTATIC_OP_SUBTRACT:
+ {
+ const float fac = opop->operation == IDOVERRIDESTATIC_OP_ADD ? 1.0 : -1.0;
+ const int other_op = opop->operation == IDOVERRIDESTATIC_OP_ADD ? IDOVERRIDESTATIC_OP_SUBTRACT : IDOVERRIDESTATIC_OP_ADD;
+ bool do_set = true;
+ array_b = (len_local > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_b) * len_local, __func__) : array_stack_b;
+ RNA_property_float_get_array(ptr_local, prop_local, array_b);
+ for (int i = len_local; i--;) {
+ array_b[i] = fac * (array_b[i] - array_a[i]);
+ if (array_b[i] < prop_min || array_b[i] > prop_max) {
+ opop->operation = other_op;
+ for (int j = len_local; j--;) {
+ array_b[j] = j >= i ? -array_b[j] : fac * (array_a[j] - array_b[j]);
+ if (array_b[j] < prop_min || array_b[j] > prop_max) {
+ /* We failed to find a suitable diff op,
+ * fall back to plain REPLACE one. */
+ opop->operation = IDOVERRIDESTATIC_OP_REPLACE;
+ do_set = false;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ if (do_set) {
+ changed = true;
+ RNA_property_float_set_array(ptr_storage, prop_storage, array_b);
+ }
+ if (array_b != array_stack_b) MEM_freeN(array_b);
+ break;
+ }
+ case IDOVERRIDESTATIC_OP_MULTIPLY:
+ {
+ bool do_set = true;
+ array_b = (len_local > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_b) * len_local, __func__) : array_stack_b;
+ RNA_property_float_get_array(ptr_local, prop_local, array_b);
+ for (int i = len_local; i--;) {
+ array_b[i] = array_a[i] == 0.0f ? array_b[i] : array_b[i] / array_a[i];
+ if (array_b[i] < prop_min || array_b[i] > prop_max) {
+ opop->operation = IDOVERRIDESTATIC_OP_REPLACE;
+ do_set = false;
+ break;
+ }
+ }
+ if (do_set) {
+ changed = true;
+ RNA_property_float_set_array(ptr_storage, prop_storage, array_b);
+ }
+ if (array_b != array_stack_b) MEM_freeN(array_b);
+ break;
+ }
+ default:
+ BLI_assert(0 && "Unsupported RNA override diff operation on float");
+ break;
+ }
+
+ if (array_a != array_stack_a) MEM_freeN(array_a);
+ }
+ else {
+ const float value = RNA_property_float_get_index(ptr_reference, prop_reference, index);
+
+ switch (opop->operation) {
+ case IDOVERRIDESTATIC_OP_ADD:
+ case IDOVERRIDESTATIC_OP_SUBTRACT:
+ {
+ const float fac = opop->operation == IDOVERRIDESTATIC_OP_ADD ? 1.0f : -1.0f;
+ const int other_op = opop->operation == IDOVERRIDESTATIC_OP_ADD ? IDOVERRIDESTATIC_OP_SUBTRACT : IDOVERRIDESTATIC_OP_ADD;
+ float b = fac * (RNA_property_float_get_index(ptr_local, prop_local, index) - value);
+ if (b < prop_min || b > prop_max) {
+ opop->operation = other_op;
+ b = -b;
+ if (b < prop_min || b > prop_max) {
+ opop->operation = IDOVERRIDESTATIC_OP_REPLACE;
+ break;
+ }
+ }
+ changed = true;
+ RNA_property_float_set_index(ptr_storage, prop_storage, index, b);
+ break;
+ }
+ case IDOVERRIDESTATIC_OP_MULTIPLY:
+ {
+ const float b = RNA_property_float_get_index(ptr_local, prop_local, index) / (value == 0.0f ? 1.0f : value);
+ if (b < prop_min || b > prop_max) {
+ opop->operation = IDOVERRIDESTATIC_OP_REPLACE;
+ break;
+ }
+ changed = true;
+ RNA_property_float_set_index(ptr_storage, prop_storage, index, b);
+ break;
+ }
+ default:
+ BLI_assert(0 && "Unsupported RNA override diff operation on float");
+ break;
+ }
+ }
+ }
+ else {
+ const float value = RNA_property_float_get(ptr_reference, prop_reference);
+
+ switch (opop->operation) {
+ case IDOVERRIDESTATIC_OP_ADD:
+ case IDOVERRIDESTATIC_OP_SUBTRACT:
+ {
+ const float fac = opop->operation == IDOVERRIDESTATIC_OP_ADD ? 1.0f : -1.0f;
+ const int other_op = opop->operation == IDOVERRIDESTATIC_OP_ADD ? IDOVERRIDESTATIC_OP_SUBTRACT : IDOVERRIDESTATIC_OP_ADD;
+ float b = fac * (RNA_property_float_get(ptr_local, prop_local) - value);
+ if (b < prop_min || b > prop_max) {
+ opop->operation = other_op;
+ b = -b;
+ if (b < prop_min || b > prop_max) {
+ opop->operation = IDOVERRIDESTATIC_OP_REPLACE;
+ break;
+ }
+ }
+ changed = true;
+ RNA_property_float_set(ptr_storage, prop_storage, b);
+ break;
+ }
+ case IDOVERRIDESTATIC_OP_MULTIPLY:
+ {
+ const float b = RNA_property_float_get(ptr_local, prop_local) / (value == 0.0f ? 1.0f : value);
+ if (b < prop_min || b > prop_max) {
+ opop->operation = IDOVERRIDESTATIC_OP_REPLACE;
+ break;
+ }
+ changed = true;
+ RNA_property_float_set(ptr_storage, prop_storage, b);
+ break;
+ }
+ default:
+ BLI_assert(0 && "Unsupported RNA override diff operation on float");
+ break;
+ }
+ }
+ return true;
+ }
+ case PROP_ENUM:
+ /* TODO support add/sub, for bitflags? */
+ BLI_assert(0 && "Enum properties support no override diff operation");
+ break;
+ case PROP_POINTER:
+ BLI_assert(0 && "Pointer properties support no override diff operation");
+ break;
+ case PROP_STRING:
+ BLI_assert(0 && "String properties support no override diff operation");
+ break;
+ case PROP_COLLECTION:
+ /* XXX TODO support this of course... */
+ BLI_assert(0 && "Collection properties support no override diff operation");
+ break;
+ default:
+ break;
+ }
+
+ return changed;
+}
+
+bool rna_property_override_apply_default(
+ PointerRNA *ptr_dst, PointerRNA *ptr_src, PointerRNA *ptr_storage,
+ PropertyRNA *prop_dst, PropertyRNA *prop_src, PropertyRNA *prop_storage,
+ const int len_dst, const int len_src, const int len_storage,
+ IDOverrideStaticPropertyOperation *opop)
+{
+ BLI_assert(len_dst == len_src && (!ptr_storage || len_dst == len_storage));
+ UNUSED_VARS_NDEBUG(len_src, len_storage);
+
+ const int index = opop->subitem_reference_index;
+ const short override_op = opop->operation;
+
+ switch (RNA_property_type(prop_dst)) {
+ case PROP_BOOLEAN:
+ if (len_dst) {
+ if (index == -1) {
+ int array_stack_a[RNA_STACK_ARRAY];
+ int *array_a;
+
+ array_a = (len_dst > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_a) * len_dst, __func__) : array_stack_a;
+
+ RNA_property_boolean_get_array(ptr_src, prop_src, array_a);
+
+ switch (override_op) {
+ case IDOVERRIDESTATIC_OP_REPLACE:
+ RNA_property_boolean_set_array(ptr_dst, prop_dst, array_a);
+ break;
+ default:
+ BLI_assert(0 && "Unsupported RNA override operation on boolean");
+ return false;
+ }
+
+ if (array_a != array_stack_a) MEM_freeN(array_a);
+ }
+ else {
+ const int value = RNA_property_boolean_get_index(ptr_src, prop_src, index);
+
+ switch (override_op) {
+ case IDOVERRIDESTATIC_OP_REPLACE:
+ RNA_property_boolean_set_index(ptr_dst, prop_dst, index, value);
+ break;
+ default:
+ BLI_assert(0 && "Unsupported RNA override operation on boolean");
+ return false;
+ }
+ }
+ }
+ else {
+ const int value = RNA_property_boolean_get(ptr_src, prop_src);
+
+ switch (override_op) {
+ case IDOVERRIDESTATIC_OP_REPLACE:
+ RNA_property_boolean_set(ptr_dst, prop_dst, value);
+ break;
+ default:
+ BLI_assert(0 && "Unsupported RNA override operation on boolean");
+ return false;
+ }
+ }
+ return true;
+ case PROP_INT:
+ if (len_dst) {
+ if (index == -1) {
+ int array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY];
+ int *array_a, *array_b;
+
+ array_a = (len_dst > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_a) * len_dst, __func__) : array_stack_a;
+
+ switch (override_op) {
+ case IDOVERRIDESTATIC_OP_REPLACE:
+ RNA_property_int_get_array(ptr_src, prop_src, array_a);
+ RNA_property_int_set_array(ptr_dst, prop_dst, array_a);
+ break;
+ case IDOVERRIDESTATIC_OP_ADD:
+ case IDOVERRIDESTATIC_OP_SUBTRACT:
+ RNA_property_int_get_array(ptr_dst, prop_dst, array_a);
+ array_b = (len_dst > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_b) * len_dst, __func__) : array_stack_b;
+ RNA_property_int_get_array(ptr_storage, prop_storage, array_b);
+ if (override_op == IDOVERRIDESTATIC_OP_ADD) {
+ for (int i = len_dst; i--;) array_a[i] += array_b[i];
+ }
+ else {
+ for (int i = len_dst; i--;) array_a[i] -= array_b[i];
+ }
+ RNA_property_int_set_array(ptr_dst, prop_dst, array_a);
+ if (array_b != array_stack_b) MEM_freeN(array_b);
+ break;
+ default:
+ BLI_assert(0 && "Unsupported RNA override operation on integer");
+ return false;
+ }
+
+ if (array_a != array_stack_a) MEM_freeN(array_a);
+ }
+ else {
+ const int storage_value = ptr_storage ? RNA_property_int_get_index(ptr_storage, prop_storage, index) : 0;
+
+ switch (override_op) {
+ case IDOVERRIDESTATIC_OP_REPLACE:
+ RNA_property_int_set_index(ptr_dst, prop_dst, index,
+ RNA_property_int_get_index(ptr_src, prop_src, index));
+ break;
+ case IDOVERRIDESTATIC_OP_ADD:
+ RNA_property_int_set_index(ptr_dst, prop_dst, index,
+ RNA_property_int_get_index(ptr_dst, prop_dst, index) - storage_value);
+ break;
+ case IDOVERRIDESTATIC_OP_SUBTRACT:
+ RNA_property_int_set_index(ptr_dst, prop_dst, index,
+ RNA_property_int_get_index(ptr_dst, prop_dst, index) - storage_value);
+ break;
+ default:
+ BLI_assert(0 && "Unsupported RNA override operation on integer");
+ return false;
+ }
+ }
+ }
+ else {
+ const int storage_value = ptr_storage ? RNA_property_int_get(ptr_storage, prop_storage) : 0;
+
+ switch (override_op) {
+ case IDOVERRIDESTATIC_OP_REPLACE:
+ RNA_property_int_set(ptr_dst, prop_dst, RNA_property_int_get(ptr_src, prop_src));
+ break;
+ case IDOVERRIDESTATIC_OP_ADD:
+ RNA_property_int_set(ptr_dst, prop_dst, RNA_property_int_get(ptr_dst, prop_dst) + storage_value);
+ break;
+ case IDOVERRIDESTATIC_OP_SUBTRACT:
+ RNA_property_int_set(ptr_dst, prop_dst, RNA_property_int_get(ptr_dst, prop_dst) - storage_value);
+ break;
+ default:
+ BLI_assert(0 && "Unsupported RNA override operation on integer");
+ return false;
+ }
+ }
+ return true;
+ case PROP_FLOAT:
+ if (len_dst) {
+ if (index == -1) {
+ float array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY];
+ float *array_a, *array_b;
+
+ array_a = (len_dst > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_a) * len_dst, __func__) : array_stack_a;
+
+ switch (override_op) {
+ case IDOVERRIDESTATIC_OP_REPLACE:
+ RNA_property_float_get_array(ptr_src, prop_src, array_a);
+ RNA_property_float_set_array(ptr_dst, prop_dst, array_a);
+ break;
+ case IDOVERRIDESTATIC_OP_ADD:
+ case IDOVERRIDESTATIC_OP_SUBTRACT:
+ case IDOVERRIDESTATIC_OP_MULTIPLY:
+ RNA_property_float_get_array(ptr_dst, prop_dst, array_a);
+ array_b = (len_dst > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_b) * len_dst, __func__) : array_stack_b;
+ RNA_property_float_get_array(ptr_storage, prop_storage, array_b);
+ if (override_op == IDOVERRIDESTATIC_OP_ADD) {
+ for (int i = len_dst; i--;) array_a[i] += array_b[i];
+ }
+ else if (override_op == IDOVERRIDESTATIC_OP_SUBTRACT) {
+ for (int i = len_dst; i--;) array_a[i] -= array_b[i];
+ }
+ else {
+ for (int i = len_dst; i--;) array_a[i] *= array_b[i];
+ }
+ RNA_property_float_set_array(ptr_dst, prop_dst, array_a);
+ if (array_b != array_stack_b) MEM_freeN(array_b);
+ break;
+ default:
+ BLI_assert(0 && "Unsupported RNA override operation on float");
+ return false;
+ }
+
+ if (array_a != array_stack_a) MEM_freeN(array_a);
+ }
+ else {
+ const float storage_value = ptr_storage ? RNA_property_float_get_index(ptr_storage, prop_storage, index) : 0.0f;
+
+ switch (override_op) {
+ case IDOVERRIDESTATIC_OP_REPLACE:
+ RNA_property_float_set_index(ptr_dst, prop_dst, index,
+ RNA_property_float_get_index(ptr_src, prop_src, index));
+ break;
+ case IDOVERRIDESTATIC_OP_ADD:
+ RNA_property_float_set_index(ptr_dst, prop_dst, index,
+ RNA_property_float_get_index(ptr_dst, prop_dst, index) + storage_value);
+ break;
+ case IDOVERRIDESTATIC_OP_SUBTRACT:
+ RNA_property_float_set_index(ptr_dst, prop_dst, index,
+ RNA_property_float_get_index(ptr_dst, prop_dst, index) - storage_value);
+ break;
+ case IDOVERRIDESTATIC_OP_MULTIPLY:
+ RNA_property_float_set_index(ptr_dst, prop_dst, index,
+ RNA_property_float_get_index(ptr_dst, prop_dst, index) * storage_value);
+ break;
+ default:
+ BLI_assert(0 && "Unsupported RNA override operation on float");
+ return false;
+ }
+ }
+ }
+ else {
+ const float storage_value = ptr_storage ? RNA_property_float_get(ptr_storage, prop_storage) : 0.0f;
+
+ switch (override_op) {
+ case IDOVERRIDESTATIC_OP_REPLACE:
+ RNA_property_float_set(ptr_dst, prop_dst, RNA_property_float_get(ptr_src, prop_src));
+ break;
+ case IDOVERRIDESTATIC_OP_ADD:
+ RNA_property_float_set(ptr_dst, prop_dst, RNA_property_float_get(ptr_dst, prop_dst) + storage_value);
+ break;
+ case IDOVERRIDESTATIC_OP_SUBTRACT:
+ RNA_property_float_set(ptr_dst, prop_dst, RNA_property_float_get(ptr_dst, prop_dst) - storage_value);
+ break;
+ case IDOVERRIDESTATIC_OP_MULTIPLY:
+ RNA_property_float_set(ptr_dst, prop_dst, RNA_property_float_get(ptr_dst, prop_dst) * storage_value);
+ break;
+ default:
+ BLI_assert(0 && "Unsupported RNA override operation on float");
+ return false;
+ }
+ }
+ return true;
+ case PROP_ENUM:
+ {
+ const int value = RNA_property_enum_get(ptr_src, prop_src);
+
+ switch (override_op) {
+ case IDOVERRIDESTATIC_OP_REPLACE:
+ RNA_property_enum_set(ptr_dst, prop_dst, value);
+ break;
+ /* TODO support add/sub, for bitflags? */
+ default:
+ BLI_assert(0 && "Unsupported RNA override operation on enum");
+ return false;
+ }
+ return true;
+ }
+ case PROP_POINTER:
+ {
+ PointerRNA value = RNA_property_pointer_get(ptr_src, prop_src);
+
+ switch (override_op) {
+ case IDOVERRIDESTATIC_OP_REPLACE:
+ RNA_property_pointer_set(ptr_dst, prop_dst, value);
+ break;
+ default:
+ BLI_assert(0 && "Unsupported RNA override operation on pointer");
+ return false;
+ }
+ return true;
+ }
+ case PROP_STRING:
+ {
+ char buff[256];
+ char *value = RNA_property_string_get_alloc(ptr_src, prop_src, buff, sizeof(buff), NULL);
+
+ switch (override_op) {
+ case IDOVERRIDESTATIC_OP_REPLACE:
+ RNA_property_string_set(ptr_dst, prop_dst, value);
+ break;
+ default:
+ BLI_assert(0 && "Unsupported RNA override operation on string");
+ return false;
+ }
+
+ if (value != buff) MEM_freeN(value);
+ return true;
+ }
+ default:
+ /* TODO PROP_COLLECTION of course! */
+ return false;
+ }
+
+ return false;
+}
+
+
#else
@@ -1259,6 +2265,11 @@ static void rna_def_property(BlenderRNA *brna)
RNA_def_property_boolean_funcs(prop, "rna_Property_animatable_get", NULL);
RNA_def_property_ui_text(prop, "Animatable", "Property is animatable through RNA");
+ prop = RNA_def_property(srna, "is_overridable", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_boolean_funcs(prop, "rna_Property_overridable_get", NULL);
+ RNA_def_property_ui_text(prop, "Overridable", "Property is overridable through RNA");
+
prop = RNA_def_property(srna, "is_required", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_boolean_funcs(prop, "rna_Property_is_required_get", NULL);
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 5600935c567..785f805a33e 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -1496,7 +1496,7 @@ static void rna_Scene_editmesh_select_mode_set(PointerRNA *ptr, const int *value
}
}
-static void rna_Scene_editmesh_select_mode_update(Main *UNUSED(bmain), bContext *C, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
+static void rna_Scene_editmesh_select_mode_update(bContext *C, PointerRNA *UNUSED(ptr))
{
ViewLayer *view_layer = CTX_data_view_layer(C);
Mesh *me = NULL;
@@ -1746,7 +1746,7 @@ static char *rna_CurvePaintSettings_path(PointerRNA *UNUSED(ptr))
}
/* generic function to recalc geometry */
-static void rna_EditMesh_update(Main *UNUSED(bmain), bContext *C, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
+static void rna_EditMesh_update(bContext *C, PointerRNA *UNUSED(ptr))
{
ViewLayer *view_layer = CTX_data_view_layer(C);
Mesh *me = NULL;
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index b245d12bbd5..7d8bf4949d5 100644
--- a/source/blender/makesrna/intern/rna_scene_api.c
+++ b/source/blender/makesrna/intern/rna_scene_api.c
@@ -176,19 +176,19 @@ static void rna_Scene_ray_cast(
int *r_success, float r_location[3], float r_normal[3], int *r_index,
Object **r_ob, float r_obmat[16])
{
- RenderEngineType *engine;
+ RenderEngineType *engine_type;
if (engine_id == NULL || engine_id[0] == '\0') {
- engine = RE_engines_find(scene->view_render.engine_id);
+ engine_type = RE_engines_find(scene->view_render.engine_id);
}
else {
- engine = RE_engines_find(engine_id);
+ engine_type = RE_engines_find(engine_id);
}
normalize_v3(direction);
SnapObjectContext *sctx = ED_transform_snap_object_context_create(
- G.main, scene, view_layer, engine, 0);
+ G.main, scene, view_layer, engine_type, 0);
bool ret = ED_transform_snap_object_project_ray_ex(
sctx,
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index a2edb072102..ddcf525c3c8 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -166,7 +166,7 @@ static void rna_ParticleEdit_redo(bContext *C, PointerRNA *UNUSED(ptr))
psys_free_path_cache(edit->psys, edit);
}
-static void rna_ParticleEdit_update(Main *UNUSED(bmain), Scene *UNUSED(scene), bContext *C, PointerRNA *UNUSED(ptr))
+static void rna_ParticleEdit_update(bContext *C, PointerRNA *UNUSED(ptr))
{
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = OBACT(view_layer);
@@ -280,12 +280,13 @@ static void rna_Sculpt_update(bContext *C, PointerRNA *UNUSED(ptr))
}
}
-static void rna_Sculpt_ShowDiffuseColor_update(bContext *C, Scene *scene, PointerRNA *UNUSED(ptr))
+static void rna_Sculpt_ShowDiffuseColor_update(bContext *C, PointerRNA *UNUSED(ptr))
{
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = OBACT(view_layer);
if (ob && ob->sculpt) {
+ Scene *scene = CTX_data_scene(C);
Sculpt *sd = scene->toolsettings->sculpt;
ob->sculpt->show_diffuse_color = ((sd->flags & SCULPT_SHOW_DIFFUSE) != 0);
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index fbc29039539..61ac81a6d1c 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -550,6 +550,8 @@ static StructRNA *rna_Sequence_refine(struct PointerRNA *ptr)
return &RNA_GaussianBlurSequence;
case SEQ_TYPE_TEXT:
return &RNA_TextSequence;
+ case SEQ_TYPE_COLORMIX:
+ return &RNA_ColorMixSequence;
default:
return &RNA_Sequence;
}
@@ -1338,6 +1340,24 @@ static const EnumPropertyItem blend_mode_items[] = {
{SEQ_TYPE_GAMCROSS, "GAMMA_CROSS", 0, "Gamma Cross", ""},
{SEQ_TYPE_MUL, "MULTIPLY", 0, "Multiply", ""},
{SEQ_TYPE_OVERDROP, "OVER_DROP", 0, "Over Drop", ""},
+ {SEQ_TYPE_LIGHTEN, "LIGHTEN", 0, "Lighten", ""},
+ {SEQ_TYPE_DARKEN, "DARKEN", 0, "Darken", ""},
+ {SEQ_TYPE_SCREEN, "SCREEN", 0, "Screen", ""},
+ {SEQ_TYPE_OVERLAY, "OVERLAY", 0, "Overlay", ""},
+ {SEQ_TYPE_DODGE, "DODGE", 0, "Dodge", ""},
+ {SEQ_TYPE_BURN, "BURN", 0, "Burn", ""},
+ {SEQ_TYPE_LINEAR_BURN, "LINEAR_BURN", 0, "Linear Burn", ""},
+ {SEQ_TYPE_SOFT_LIGHT, "SOFT_LIGHT", 0, "Soft Light", ""},
+ {SEQ_TYPE_HARD_LIGHT, "HARD_LIGHT", 0, "Hard Light", ""},
+ {SEQ_TYPE_PIN_LIGHT, "PIN_LIGHT", 0, "Pin Light", ""},
+ {SEQ_TYPE_LIN_LIGHT, "LINEAR_LIGHT", 0, "Linear Light", ""},
+ {SEQ_TYPE_VIVID_LIGHT, "VIVID_LIGHT", 0, "Vivid Light", ""},
+ {SEQ_TYPE_BLEND_COLOR, "COLOR", 0, "Color", ""},
+ {SEQ_TYPE_HUE, "HUE", 0, "Hue", ""},
+ {SEQ_TYPE_SATURATION, "SATURATION", 0, "Saturation", ""},
+ {SEQ_TYPE_VALUE, "VALUE", 0, "Value", ""},
+ {SEQ_TYPE_DIFFERENCE, "DIFFERENCE", 0, "Difference", ""},
+ {SEQ_TYPE_EXCLUSION, "EXCLUSION", 0, "Exclusion", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -1411,6 +1431,7 @@ static void rna_def_sequence(BlenderRNA *brna)
{SEQ_TYPE_ADJUSTMENT, "ADJUSTMENT", 0, "Adjustment Layer", ""},
{SEQ_TYPE_GAUSSIAN_BLUR, "GAUSSIAN_BLUR", 0, "Gaussian Blur", ""},
{SEQ_TYPE_TEXT, "TEXT", 0, "Text", ""},
+ {SEQ_TYPE_COLORMIX, "COLORMIX", 0, "Color Mix", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -2378,6 +2399,49 @@ static void rna_def_text(StructRNA *srna)
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
}
+static void rna_def_color_mix(StructRNA *srna)
+{
+ static EnumPropertyItem blend_color_items[] = {
+ {SEQ_TYPE_ADD, "ADD", 0, "Add", ""},
+ {SEQ_TYPE_SUB, "SUBTRACT", 0, "Subtract", ""},
+ {SEQ_TYPE_MUL, "MULTIPLY", 0, "Multiply", ""},
+ {SEQ_TYPE_LIGHTEN, "LIGHTEN", 0, "Lighten", ""},
+ {SEQ_TYPE_DARKEN, "DARKEN", 0, "Darken", ""},
+ {SEQ_TYPE_SCREEN, "SCREEN", 0, "Screen", ""},
+ {SEQ_TYPE_OVERLAY, "OVERLAY", 0, "Overlay", ""},
+ {SEQ_TYPE_DODGE, "DODGE", 0, "Dodge", ""},
+ {SEQ_TYPE_BURN, "BURN", 0, "Burn", ""},
+ {SEQ_TYPE_LINEAR_BURN, "LINEAR_BURN", 0, "Linear Burn", ""},
+ {SEQ_TYPE_SOFT_LIGHT, "SOFT_LIGHT", 0, "Soft Light", ""},
+ {SEQ_TYPE_HARD_LIGHT, "HARD_LIGHT", 0, "Hard Light", ""},
+ {SEQ_TYPE_PIN_LIGHT, "PIN_LIGHT", 0, "Pin Light", ""},
+ {SEQ_TYPE_LIN_LIGHT, "LINEAR_LIGHT", 0, "Linear Light", ""},
+ {SEQ_TYPE_VIVID_LIGHT, "VIVID_LIGHT", 0, "Vivid Light", ""},
+ {SEQ_TYPE_BLEND_COLOR, "COLOR", 0, "Color", ""},
+ {SEQ_TYPE_HUE, "HUE", 0, "Hue", ""},
+ {SEQ_TYPE_SATURATION, "SATURATION", 0, "Saturation", ""},
+ {SEQ_TYPE_VALUE, "VALUE", 0, "Value", ""},
+ {SEQ_TYPE_DIFFERENCE, "DIFFERENCE", 0, "Difference", ""},
+ {SEQ_TYPE_EXCLUSION, "EXCLUSION", 0, "Exclusion", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "ColorMixVars", "effectdata");
+
+ prop = RNA_def_property(srna, "blend_effect", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "blend_effect");
+ RNA_def_property_enum_items(prop, blend_color_items);
+ RNA_def_property_ui_text(prop, "Blend Effect", "Method for controlling how the strip combines with other strips");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
+
+ prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Blend Factor", "Percentage of how much the strip's colors affect other strips");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
+}
+
static EffectInfo def_effects[] = {
{"AddSequence", "Add Sequence", "Add Sequence", NULL, 2},
{"AdjustmentSequence", "Adjustment Layer Sequence",
@@ -2404,6 +2468,7 @@ static EffectInfo def_effects[] = {
rna_def_gaussian_blur, 1},
{"TextSequence", "Text Sequence", "Sequence strip creating text",
rna_def_text, 0},
+ {"ColorMixSequence", "Color Mix Sequence", "Color Mix Sequence", rna_def_color_mix, 2},
{"", "", "", NULL, 0}
};
diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c
index e1d3f3958a5..d447d2972f6 100644
--- a/source/blender/makesrna/intern/rna_sequencer_api.c
+++ b/source/blender/makesrna/intern/rna_sequencer_api.c
@@ -475,6 +475,7 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop)
{SEQ_TYPE_ADJUSTMENT, "ADJUSTMENT", 0, "Adjustment Layer", ""},
{SEQ_TYPE_GAUSSIAN_BLUR, "GAUSSIAN_BLUR", 0, "Gaussian Blur", ""},
{SEQ_TYPE_TEXT, "TEXT", 0, "Text", ""},
+ {SEQ_TYPE_COLORMIX, "COLORMIX", 0, "Color Mix", ""},
{0, NULL, 0, NULL, NULL}
};
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index a38136eed53..82283019fc8 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -227,6 +227,11 @@ static const EnumPropertyItem buttons_texture_context_items[] = {
{0, NULL, 0, NULL, NULL}
};
+static const EnumPropertyItem buttons_collection_context_items[] = {
+ {SB_COLLECTION_CTX_VIEW_LAYER, "VIEW_LAYER", ICON_RENDERLAYERS, "", "Show material textures"},
+ {SB_COLLECTION_CTX_GROUP, "GROUP", ICON_GROUP, "", "Show world textures"},
+ {0, NULL, 0, NULL, NULL}
+};
static const EnumPropertyItem fileselectparams_recursion_level_items[] = {
{0, "NONE", 0, "None", "Only list current directory's content, with no recursion"},
@@ -2745,6 +2750,11 @@ static void rna_def_space_buttons(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Limited Texture Context",
"Use the limited version of texture user (for 'old shading' mode)");
+ prop = RNA_def_property(srna, "collection_context", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, buttons_collection_context_items);
+ RNA_def_property_ui_text(prop, "Collection Context", "Which collection we want to show");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_PROPERTIES, NULL);
+
/* pinned data */
prop = RNA_def_property(srna, "pin_id", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "pinid");
diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c
index ad3ed6f55ac..51bdc0ea9ff 100644
--- a/source/blender/makesrna/intern/rna_ui_api.c
+++ b/source/blender/makesrna/intern/rna_ui_api.c
@@ -60,8 +60,8 @@ const EnumPropertyItem rna_enum_icon_items[] = {
#ifdef RNA_RUNTIME
-const char *rna_translate_ui_text(const char *text, const char *text_ctxt, StructRNA *type, PropertyRNA *prop,
- int translate)
+const char *rna_translate_ui_text(
+ const char *text, const char *text_ctxt, StructRNA *type, PropertyRNA *prop, int translate)
{
/* Also return text if UI labels translation is disabled. */
if (!text || !text[0] || !translate || !BLT_translate_iface()) {
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index cbbe0df1d60..1cdd43eeffc 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -827,6 +827,16 @@ static void rna_def_userdef_theme_ui_wcol_state(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Driven Selected", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+ prop = RNA_def_property(srna, "inner_overridden", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Overridden", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "inner_overridden_sel", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Overridden Selected", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
prop = RNA_def_property(srna, "blend", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_ui_text(prop, "Blend", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index 7d821ee407b..36f07db727b 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -36,6 +36,8 @@
#include "BLT_translation.h"
+#include "BKE_workspace.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -467,6 +469,7 @@ const EnumPropertyItem rna_enum_wm_report_items[] = {
#include "WM_api.h"
+#include "DNA_object_types.h"
#include "DNA_workspace_types.h"
#include "ED_screen.h"
@@ -475,7 +478,6 @@ const EnumPropertyItem rna_enum_wm_report_items[] = {
#include "BKE_global.h"
#include "BKE_idprop.h"
-#include "BKE_workspace.h"
#include "MEM_guardedalloc.h"
@@ -755,6 +757,49 @@ static void rna_workspace_screen_update(bContext *C, PointerRNA *ptr)
}
}
+static PointerRNA rna_Window_view_layer_get(PointerRNA *ptr)
+{
+ wmWindow *win = ptr->data;
+ Scene *scene = WM_window_get_active_scene(win);
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+ ViewLayer *view_layer = BKE_workspace_view_layer_get(workspace, scene);
+ PointerRNA scene_ptr;
+
+ RNA_id_pointer_create(&scene->id, &scene_ptr);
+ return rna_pointer_inherit_refine(&scene_ptr, &RNA_ViewLayer, view_layer);
+}
+
+static void rna_Window_view_layer_set(PointerRNA *ptr, PointerRNA value)
+{
+ wmWindow *win = ptr->data;
+ Scene *scene = WM_window_get_active_scene(win);
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+
+ BKE_workspace_view_layer_set(workspace, value.data, scene);
+}
+
+#ifdef USE_WORKSPACE_MODE
+
+static int rna_Window_object_mode_get(PointerRNA *ptr)
+{
+ wmWindow *win = ptr->data;
+ Scene *scene = WM_window_get_active_scene(win);
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+
+ return (int)BKE_workspace_object_mode_get(workspace, scene);
+}
+
+static void rna_Window_object_mode_set(PointerRNA *ptr, int value)
+{
+ wmWindow *win = ptr->data;
+ Scene *scene = WM_window_get_active_scene(win);
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+
+ BKE_workspace_object_mode_set(workspace, scene, value);
+}
+
+#endif /* USE_WORKSPACE_MODE */
+
static PointerRNA rna_KeyMapItem_properties_get(PointerRNA *ptr)
{
wmKeyMapItem *kmi = ptr->data;
@@ -2024,6 +2069,20 @@ static void rna_def_window(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_NEVER_NULL | PROP_EDITABLE | PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, 0, "rna_workspace_screen_update");
+ prop = RNA_def_property(srna, "view_layer", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "ViewLayer");
+ RNA_def_property_pointer_funcs(prop, "rna_Window_view_layer_get", "rna_Window_view_layer_set", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Active View Layer", "The active workspace view layer showing in the window");
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_NULL);
+ RNA_def_property_update(prop, NC_SCREEN | ND_LAYER, NULL);
+
+#ifdef USE_WORKSPACE_MODE
+ prop = RNA_def_property(srna, "object_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_object_mode_items);
+ RNA_def_property_enum_funcs(prop, "rna_Window_object_mode_get", "rna_Window_object_mode_set", NULL);
+ RNA_def_property_ui_text(prop, "Mode", "Object interaction mode used in this window");
+#endif
+
prop = RNA_def_property(srna, "x", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "posx");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
diff --git a/source/blender/makesrna/intern/rna_workspace.c b/source/blender/makesrna/intern/rna_workspace.c
index 7e7b2eeccd7..0bed91f2807 100644
--- a/source/blender/makesrna/intern/rna_workspace.c
+++ b/source/blender/makesrna/intern/rna_workspace.c
@@ -67,22 +67,6 @@ static PointerRNA rna_workspace_screens_item_get(CollectionPropertyIterator *ite
return rna_pointer_inherit_refine(&iter->parent, &RNA_Screen, screen);
}
-#ifdef USE_WORKSPACE_MODE
-
-static int rna_workspace_object_mode_get(PointerRNA *ptr)
-{
- WorkSpace *workspace = ptr->data;
- return (int)BKE_workspace_object_mode_get(workspace);
-}
-
-static void rna_workspace_object_mode_set(PointerRNA *ptr, int value)
-{
- WorkSpace *workspace = ptr->data;
- BKE_workspace_object_mode_set(workspace, value);
-}
-
-#endif /* USE_WORKSPACE_MODE */
-
void rna_workspace_transform_orientations_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
WorkSpace *workspace = ptr->id.data;
@@ -95,30 +79,6 @@ static PointerRNA rna_workspace_transform_orientations_item_get(CollectionProper
return rna_pointer_inherit_refine(&iter->parent, &RNA_TransformOrientation, transform_orientation);
}
-static PointerRNA rna_workspace_view_layer_get(PointerRNA *ptr)
-{
- WorkSpace *workspace = ptr->data;
- ViewLayer *view_layer = BKE_workspace_view_layer_get(workspace);
-
- /* XXX hmrf... lookup in getter... but how could we avoid it? */
- for (Scene *scene = G.main->scene.first; scene; scene = scene->id.next) {
- if (BLI_findindex(&scene->view_layers, view_layer) != -1) {
- PointerRNA scene_ptr;
-
- RNA_id_pointer_create(&scene->id, &scene_ptr);
- return rna_pointer_inherit_refine(&scene_ptr, &RNA_ViewLayer, view_layer);
- }
- }
-
- return PointerRNA_NULL;
-}
-
-static void rna_workspace_view_layer_set(PointerRNA *ptr, PointerRNA value)
-{
- WorkSpace *workspace = ptr->data;
- BKE_workspace_view_layer_set(workspace, value.data);
-}
-
#else /* RNA_RUNTIME */
static void rna_def_workspace(BlenderRNA *brna)
@@ -139,13 +99,6 @@ static void rna_def_workspace(BlenderRNA *brna)
"rna_workspace_screens_item_get", NULL, NULL, NULL, NULL);
RNA_def_property_ui_text(prop, "Screens", "Screen layouts of a workspace");
-#ifdef USE_WORKSPACE_MODE
- prop = RNA_def_property(srna, "object_mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_enum_object_mode_items);
- RNA_def_property_enum_funcs(prop, "rna_workspace_object_mode_get", "rna_workspace_object_mode_set", NULL);
- RNA_def_property_ui_text(prop, "Mode", "Object interaction mode");
-#endif
-
prop = RNA_def_property(srna, "tool_keymap", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "tool.keymap");
RNA_def_property_ui_text(prop, "Active Tool", "Currently active tool keymap");
@@ -168,14 +121,6 @@ static void rna_def_workspace(BlenderRNA *brna)
"rna_workspace_transform_orientations_item_get", NULL, NULL, NULL, NULL);
RNA_def_property_ui_text(prop, "Transform Orientations", "");
- prop = RNA_def_property(srna, "view_layer", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "ViewLayer");
- RNA_def_property_pointer_funcs(prop, "rna_workspace_view_layer_get", "rna_workspace_view_layer_set",
- NULL, NULL);
- RNA_def_property_ui_text(prop, "Active View Layer", "The active view layer used in this workspace");
- RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_NULL);
- RNA_def_property_update(prop, NC_SCREEN | ND_LAYER, NULL);
-
/* View Render */
prop = RNA_def_property(srna, "view_render", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
diff --git a/source/blender/python/gawain/gwn_py_types.c b/source/blender/python/gawain/gwn_py_types.c
index cc448d9ed90..5b602e85a12 100644
--- a/source/blender/python/gawain/gwn_py_types.c
+++ b/source/blender/python/gawain/gwn_py_types.c
@@ -671,6 +671,26 @@ static PyObject *bpygwn_VertBatch_draw(BPyGwn_Batch *self)
Py_RETURN_NONE;
}
+static PyObject *bpygwn_VertBatch_program_use_begin(BPyGwn_Batch *self)
+{
+ if (!glIsProgram(self->batch->program)) {
+ PyErr_SetString(PyExc_ValueError,
+ "batch program has not not set");
+ }
+ GWN_batch_program_use_begin(self->batch);
+ Py_RETURN_NONE;
+}
+
+static PyObject *bpygwn_VertBatch_program_use_end(BPyGwn_Batch *self)
+{
+ if (!glIsProgram(self->batch->program)) {
+ PyErr_SetString(PyExc_ValueError,
+ "batch program has not not set");
+ }
+ GWN_batch_program_use_end(self->batch);
+ Py_RETURN_NONE;
+}
+
static struct PyMethodDef bpygwn_VertBatch_methods[] = {
{"vertbuf_add", (PyCFunction)bpygwn_VertBatch_vertbuf_add,
METH_O, bpygwn_VertBatch_vertbuf_add_doc},
@@ -684,6 +704,10 @@ static struct PyMethodDef bpygwn_VertBatch_methods[] = {
METH_VARARGS, NULL},
{"draw", (PyCFunction) bpygwn_VertBatch_draw,
METH_NOARGS, bpygwn_VertBatch_draw_doc},
+ {"program_use_begin", (PyCFunction)bpygwn_VertBatch_program_use_begin,
+ METH_NOARGS, ""},
+ {"program_use_end", (PyCFunction)bpygwn_VertBatch_program_use_end,
+ METH_NOARGS, ""},
{NULL, NULL, 0, NULL}
};
diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c
index d49f9514b8c..36609c6f29b 100644
--- a/source/blender/python/generic/py_capi_utils.c
+++ b/source/blender/python/generic/py_capi_utils.c
@@ -412,6 +412,25 @@ PyObject *PyC_Err_Format_Prefix(PyObject *exception_type_prefix, const char *for
return NULL;
}
+/**
+ * Use for Python callbacks run directly from C,
+ * when we can't use normal methods of raising exceptions.
+ */
+void PyC_Err_PrintWithFunc(PyObject *py_func)
+{
+ /* since we return to C code we can't leave the error */
+ PyCodeObject *f_code = (PyCodeObject *)PyFunction_GET_CODE(py_func);
+ PyErr_Print();
+ PyErr_Clear();
+
+ /* use py style error */
+ fprintf(stderr, "File \"%s\", line %d, in %s\n",
+ _PyUnicode_AsString(f_code->co_filename),
+ f_code->co_firstlineno,
+ _PyUnicode_AsString(((PyFunctionObject *)py_func)->func_name)
+ );
+}
+
/* returns the exception string as a new PyUnicode object, depends on external traceback module */
#if 0
diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h
index 327d4e60954..25c88799027 100644
--- a/source/blender/python/generic/py_capi_utils.h
+++ b/source/blender/python/generic/py_capi_utils.h
@@ -38,6 +38,8 @@ PyObject * PyC_ExceptionBuffer_Simple(void);
PyObject * PyC_Object_GetAttrStringArgs(PyObject *o, Py_ssize_t n, ...);
PyObject * PyC_FrozenSetFromStrings(const char **strings);
PyObject * PyC_Err_Format_Prefix(PyObject *exception_type_prefix, const char *format, ...);
+void PyC_Err_PrintWithFunc(PyObject *py_func);
+
void PyC_FileAndNum(const char **filename, int *lineno);
void PyC_FileAndNum_Safe(const char **filename, int *lineno); /* checks python is running */
int PyC_AsArray_FAST(
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index 26fbc5d9eb2..41018468695 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -45,10 +45,6 @@ set(INC_SYS
)
set(SRC
- gpu.c
- gpu_offscreen.c
- gpu_py_matrix.c
- gpu_py_select.c
bpy.c
bpy_app.c
bpy_app_alembic.c
@@ -61,6 +57,7 @@ set(SRC
bpy_app_openvdb.c
bpy_app_sdl.c
bpy_app_translations.c
+ bpy_capi_utils.c
bpy_driver.c
bpy_interface.c
bpy_interface_atexit.c
@@ -68,6 +65,7 @@ set(SRC
bpy_library_load.c
bpy_library_write.c
bpy_manipulator_wrap.c
+ bpy_msgbus.c
bpy_operator.c
bpy_operator_wrap.c
bpy_path.c
@@ -80,12 +78,14 @@ set(SRC
bpy_rna_id_collection.c
bpy_rna_manipulator.c
bpy_traceback.c
- bpy_util.c
bpy_utils_previews.c
bpy_utils_units.c
+ gpu.c
+ gpu_offscreen.c
+ gpu_py_matrix.c
+ gpu_py_select.c
stubs.c
- gpu.h
bpy.h
bpy_app.h
bpy_app_alembic.h
@@ -98,10 +98,12 @@ set(SRC
bpy_app_openvdb.h
bpy_app_sdl.h
bpy_app_translations.h
+ bpy_capi_utils.h
bpy_driver.h
bpy_intern_string.h
bpy_library.h
bpy_manipulator_wrap.h
+ bpy_msgbus.h
bpy_operator.h
bpy_operator_wrap.h
bpy_path.h
@@ -113,9 +115,9 @@ set(SRC
bpy_rna_id_collection.h
bpy_rna_manipulator.h
bpy_traceback.h
- bpy_util.h
bpy_utils_previews.h
bpy_utils_units.h
+ gpu.h
../BPY_extern.h
)
diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c
index c576786a54c..0b791b6acaa 100644
--- a/source/blender/python/intern/bpy.c
+++ b/source/blender/python/intern/bpy.c
@@ -42,7 +42,7 @@
#include "RNA_access.h"
#include "bpy.h"
-#include "bpy_util.h"
+#include "bpy_capi_utils.h"
#include "bpy_rna.h"
#include "bpy_app.h"
#include "bpy_rna_id_collection.h"
@@ -58,6 +58,7 @@
/* external util modules */
#include "../generic/idprop_py_api.h"
+#include "bpy_msgbus.h"
#ifdef WITH_FREESTYLE
# include "BPy_Freestyle.h"
@@ -350,6 +351,7 @@ void BPy_init_modules(void)
PyModule_AddObject(mod, "app", BPY_app_struct());
PyModule_AddObject(mod, "_utils_units", BPY_utils_units());
PyModule_AddObject(mod, "_utils_previews", BPY_utils_previews_module());
+ PyModule_AddObject(mod, "msgbus", BPY_msgbus_module());
/* bpy context */
RNA_pointer_create(NULL, &RNA_Context, (void *)BPy_GetContext(), &ctx_ptr);
diff --git a/source/blender/python/intern/bpy_util.c b/source/blender/python/intern/bpy_capi_utils.c
index c15ff50df04..7232e4ea821 100644
--- a/source/blender/python/intern/bpy_util.c
+++ b/source/blender/python/intern/bpy_capi_utils.c
@@ -20,11 +20,11 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/python/intern/bpy_util.c
+/** \file blender/python/intern/bpy_capi_utils.c
* \ingroup pythonintern
*
- * This file contains blender/python utility functions for the api's internal
- * use (unrelated to 'bpy.utils')
+ * This file contains Blender/Python utility functions to help implementing API's.
+ * This is not related to a particular module.
*/
#include <Python.h>
@@ -32,7 +32,7 @@
#include "BLI_utildefines.h"
#include "BLI_dynstr.h"
-#include "bpy_util.h"
+#include "bpy_capi_utils.h"
#include "MEM_guardedalloc.h"
diff --git a/source/blender/python/intern/bpy_util.h b/source/blender/python/intern/bpy_capi_utils.h
index 466941359a8..abb37d6e30c 100644
--- a/source/blender/python/intern/bpy_util.h
+++ b/source/blender/python/intern/bpy_capi_utils.h
@@ -20,12 +20,12 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/python/intern/bpy_util.h
+/** \file blender/python/intern/bpy_capi_utils.h
* \ingroup pythonintern
*/
-#ifndef __BPY_UTIL_H__
-#define __BPY_UTIL_H__
+#ifndef __BPY_CAPI_UTILS_H__
+#define __BPY_CAPI_UTILS_H__
#if PY_VERSION_HEX < 0x03060000
# error "Python 3.6 or greater is required, you'll need to update your python."
@@ -50,4 +50,4 @@ void BPy_SetContext(struct bContext *C);
extern void bpy_context_set(struct bContext *C, PyGILState_STATE *gilstate);
extern void bpy_context_clear(struct bContext *C, PyGILState_STATE *gilstate);
-#endif /* __BPY_UTIL_H__ */
+#endif /* __BPY_CAPI_UTILS_H__ */
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index 7ddb41c3b0d..11a233461d8 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -47,7 +47,7 @@
#include "gpu.h"
#include "bpy_rna.h"
#include "bpy_path.h"
-#include "bpy_util.h"
+#include "bpy_capi_utils.h"
#include "bpy_traceback.h"
#include "bpy_intern_string.h"
diff --git a/source/blender/python/intern/bpy_interface_atexit.c b/source/blender/python/intern/bpy_interface_atexit.c
index 5c4f6ba327c..3608a26d113 100644
--- a/source/blender/python/intern/bpy_interface_atexit.c
+++ b/source/blender/python/intern/bpy_interface_atexit.c
@@ -33,7 +33,7 @@
#include "BLI_utildefines.h"
-#include "bpy_util.h"
+#include "bpy_capi_utils.h"
#include "bpy.h" /* own include */
#include "WM_api.h"
diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c
index 1b1d6294db6..4cd5e21bc22 100644
--- a/source/blender/python/intern/bpy_library_load.c
+++ b/source/blender/python/intern/bpy_library_load.c
@@ -48,7 +48,7 @@
#include "BLO_readfile.h"
-#include "bpy_util.h"
+#include "bpy_capi_utils.h"
#include "bpy_library.h"
#include "../generic/py_capi_utils.h"
diff --git a/source/blender/python/intern/bpy_library_write.c b/source/blender/python/intern/bpy_library_write.c
index c054183034a..9ca6092eab3 100644
--- a/source/blender/python/intern/bpy_library_write.c
+++ b/source/blender/python/intern/bpy_library_write.c
@@ -43,7 +43,7 @@
#include "RNA_types.h"
#include "bpy_rna.h"
-#include "bpy_util.h"
+#include "bpy_capi_utils.h"
#include "bpy_library.h"
#include "../generic/py_capi_utils.h"
diff --git a/source/blender/python/intern/bpy_msgbus.c b/source/blender/python/intern/bpy_msgbus.c
new file mode 100644
index 00000000000..945d2a9b6cc
--- /dev/null
+++ b/source/blender/python/intern/bpy_msgbus.c
@@ -0,0 +1,400 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/intern/bpy_msgbus.c
+ * \ingroup pythonintern
+ * This file defines '_bpy_msgbus' module, exposed as 'bpy.msgbus'.
+ */
+
+#include <Python.h>
+
+#include "../generic/python_utildefines.h"
+#include "../generic/py_capi_utils.h"
+#include "../mathutils/mathutils.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+#include "WM_message.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "bpy_capi_utils.h"
+#include "bpy_rna.h"
+#include "bpy_intern_string.h"
+#include "bpy_manipulator_wrap.h" /* own include */
+
+
+#include "bpy_msgbus.h" /* own include */
+
+
+/* -------------------------------------------------------------------- */
+/** \name Internal Utils
+ * \{ */
+
+#define BPY_MSGBUS_RNA_MSGKEY_DOC \
+" :arg key: Represents the type of data being subscribed to\n" \
+"\n" \
+" Arguments include\n" \
+" - :class:`bpy.types.Property` instance.\n" \
+" - :class:`bpy.types.Struct` type.\n" \
+" - (:class:`bpy.types.Struct`, str) type and property name.\n" \
+" :type key: Muliple\n"
+
+/**
+ * There are multiple ways we can get RNA from Python,
+ * it's also possible to register a type instead of an instance.
+ *
+ * This function handles converting Python to RNA subscription information.
+ *
+ * \param py_sub: See #BPY_MSGBUS_RNA_MSGKEY_DOC for description.
+ * \param msg_key_params: Message key with all members zeroed out.
+ * \return -1 on failure, 0 on success.
+ */
+static int py_msgbus_rna_key_from_py(
+ PyObject *py_sub,
+ wmMsgParams_RNA *msg_key_params,
+ const char *error_prefix)
+{
+
+ /* Allow common case, object rotation, location - etc. */
+ if (BaseMathObject_CheckExact(py_sub)) {
+ BaseMathObject *py_sub_math = (BaseMathObject *)py_sub;
+ if (py_sub_math->cb_user == NULL) {
+ PyErr_Format(
+ PyExc_TypeError,
+ "%s: math argument has no owner",
+ error_prefix);
+ return -1;
+ }
+ py_sub = py_sub_math->cb_user;
+ /* Common case will use BPy_PropertyRNA_Check below. */
+ }
+
+ if (BPy_PropertyRNA_Check(py_sub)) {
+ BPy_PropertyRNA *data_prop = (BPy_PropertyRNA *)py_sub;
+ PYRNA_PROP_CHECK_INT(data_prop);
+ msg_key_params->ptr = data_prop->ptr;
+ msg_key_params->prop = data_prop->prop;
+ }
+ else if (BPy_StructRNA_Check(py_sub)) {
+ /* note, this isn't typically used since we don't edit structs directly. */
+ BPy_StructRNA *data_srna = (BPy_StructRNA *)py_sub;
+ PYRNA_STRUCT_CHECK_INT(data_srna);
+ msg_key_params->ptr = data_srna->ptr;
+ }
+ /* TODO - property / type, not instance. */
+ else if (PyType_Check(py_sub)) {
+ StructRNA *data_type = pyrna_struct_as_srna(py_sub, false, error_prefix);
+ if (data_type == NULL) {
+ return -1;
+ }
+ msg_key_params->ptr.type = data_type;
+ }
+ else if (PyTuple_CheckExact(py_sub)) {
+ if (PyTuple_GET_SIZE(py_sub) == 2) {
+ PyObject *data_type_py = PyTuple_GET_ITEM(py_sub, 0);
+ PyObject *data_prop_py = PyTuple_GET_ITEM(py_sub, 1);
+ StructRNA *data_type = pyrna_struct_as_srna(data_type_py, false, error_prefix);
+ if (data_type == NULL) {
+ return -1;
+ }
+ if (!PyUnicode_CheckExact(data_prop_py)) {
+ PyErr_Format(
+ PyExc_TypeError,
+ "%s: expected property to be a string",
+ error_prefix);
+ return -1;
+ }
+ PointerRNA data_type_ptr = { .type = data_type, };
+ const char *data_prop_str = _PyUnicode_AsString(data_prop_py);
+ PropertyRNA *data_prop = RNA_struct_find_property(&data_type_ptr, data_prop_str);
+
+ if (data_prop == NULL) {
+ PyErr_Format(
+ PyExc_TypeError,
+ "%s: struct %.200s does not contain property %.200s",
+ error_prefix,
+ RNA_struct_identifier(data_type),
+ data_prop_str);
+ return -1;
+ }
+
+ msg_key_params->ptr.type = data_type;
+ msg_key_params->prop = data_prop;
+ }
+ else {
+ PyErr_Format(
+ PyExc_ValueError,
+ "%s: Expected a pair (type, property_id)",
+ error_prefix);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Internal Callbacks
+ * \{ */
+
+#define BPY_MSGBUS_USER_DATA_LEN 2
+
+/* Follow wmMsgNotifyFn spec */
+static void bpy_msgbus_notify(
+ bContext *C, wmMsgSubscribeKey *UNUSED(msg_key), wmMsgSubscribeValue *msg_val)
+{
+ PyGILState_STATE gilstate;
+ bpy_context_set(C, &gilstate);
+
+ PyObject *user_data = msg_val->user_data;
+ BLI_assert(PyTuple_GET_SIZE(user_data) == BPY_MSGBUS_USER_DATA_LEN);
+
+ PyObject *callback_args = PyTuple_GET_ITEM(user_data, 0);
+ PyObject *callback_notify = PyTuple_GET_ITEM(user_data, 1);
+
+ const bool is_write_ok = pyrna_write_check();
+ if (!is_write_ok) {
+ pyrna_write_set(true);
+ }
+
+ PyObject *ret = PyObject_CallObject(callback_notify, callback_args);
+
+ if (ret == NULL) {
+ PyC_Err_PrintWithFunc(callback_notify);
+ }
+ else {
+ if (ret != Py_None) {
+ PyErr_SetString(PyExc_ValueError, "the return value must be None");
+ PyC_Err_PrintWithFunc(callback_notify);
+ }
+ Py_DECREF(ret);
+ }
+
+ bpy_context_clear(C, &gilstate);
+
+ if (!is_write_ok) {
+ pyrna_write_set(false);
+ }
+}
+
+/* Follow wmMsgSubscribeValueFreeDataFn spec */
+static void bpy_msgbus_subscribe_value_free_data(
+ struct wmMsgSubscribeKey *UNUSED(msg_key), struct wmMsgSubscribeValue *msg_val)
+{
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+ Py_DECREF(msg_val->owner);
+ Py_DECREF(msg_val->user_data);
+ PyGILState_Release(gilstate);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Public Message Bus API
+ * \{ */
+
+PyDoc_STRVAR(bpy_msgbus_subscribe_rna_doc,
+".. function:: subscribe_rna(data, owner, args, notify)\n"
+"\n"
+BPY_MSGBUS_RNA_MSGKEY_DOC
+" :arg owner: Handle for this subscription (compared by identity).\n"
+" :type owner: Any type.\n"
+"\n"
+" Returns a new vector int property definition.\n"
+);
+static PyObject *bpy_msgbus_subscribe_rna(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
+{
+ const char *error_prefix = "subscribe_rna";
+ PyObject *py_sub = NULL;
+ PyObject *py_owner = NULL;
+ PyObject *callback_args = NULL;
+ PyObject *callback_notify = NULL;
+
+ enum {
+ IS_PERSISTENT = (1 << 0),
+ };
+ PyObject *py_options = NULL;
+ EnumPropertyItem py_options_enum[] = {
+ {IS_PERSISTENT, "PERSISTENT", 0, ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+ int options = 0;
+
+ static const char *_keywords[] = {
+ "key",
+ "owner",
+ "args",
+ "notify",
+ "options",
+ NULL,
+ };
+ static _PyArg_Parser _parser = {"$OOO!OO!:subscribe_rna", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
+ &py_sub, &py_owner,
+ &PyTuple_Type, &callback_args,
+ &callback_notify,
+ &PySet_Type, &py_options))
+ {
+ return NULL;
+ }
+
+ if (py_options &&
+ (pyrna_set_to_enum_bitfield(py_options_enum, py_options, &options, error_prefix)) == -1)
+ {
+ return NULL;
+ }
+
+ /* Note: we may want to have a way to pass this in. */
+ bContext *C = (bContext *)BPy_GetContext();
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ wmMsgParams_RNA msg_key_params = {0};
+
+ wmMsgSubscribeValue msg_val_params = {0};
+
+ if (py_msgbus_rna_key_from_py(py_sub, &msg_key_params, error_prefix) == -1) {
+ return NULL;
+ }
+
+ if (!PyFunction_Check(callback_notify)) {
+ PyErr_Format(
+ PyExc_TypeError,
+ "notify expects a function, found %.200s",
+ Py_TYPE(callback_notify)->tp_name);
+ return NULL;
+ }
+
+ if (options != 0) {
+ if (options & IS_PERSISTENT) {
+ msg_val_params.is_persistent = true;
+ }
+ }
+
+ /* owner can be anything. */
+ {
+ msg_val_params.owner = py_owner;
+ Py_INCREF(py_owner);
+ }
+
+ {
+ PyObject *user_data = PyTuple_New(2);
+ PyTuple_SET_ITEMS(
+ user_data,
+ Py_INCREF_RET(callback_args),
+ Py_INCREF_RET(callback_notify));
+ msg_val_params.user_data = user_data;
+ }
+
+ msg_val_params.notify = bpy_msgbus_notify;
+ msg_val_params.free_data = bpy_msgbus_subscribe_value_free_data;
+
+ WM_msg_subscribe_rna_params(mbus, &msg_key_params, &msg_val_params, __func__);
+
+ WM_msg_dump(mbus, __func__);
+
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(bpy_msgbus_publish_rna_doc,
+".. function:: publish_rna(data, owner, args, notify)\n"
+"\n"
+BPY_MSGBUS_RNA_MSGKEY_DOC
+"\n"
+" Notify subscribers of changes to this property\n"
+" (this typically doesn't need to be called explicitly since changes will automatically publish updates).\n"
+" In some cases it may be useful to publish changes explicitly using more general keys.\n"
+);
+static PyObject *bpy_msgbus_publish_rna(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
+{
+ const char *error_prefix = "publish_rna";
+ PyObject *py_sub = NULL;
+
+ static const char *_keywords[] = {
+ "key",
+ NULL,
+ };
+ static _PyArg_Parser _parser = {"$O:publish_rna", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kw, &_parser,
+ &py_sub))
+ {
+ return NULL;
+ }
+
+ /* Note: we may want to have a way to pass this in. */
+ bContext *C = (bContext *)BPy_GetContext();
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ wmMsgParams_RNA msg_key_params = {0};
+
+ if (py_msgbus_rna_key_from_py(py_sub, &msg_key_params, error_prefix) == -1) {
+ return NULL;
+ }
+
+ WM_msg_publish_rna_params(mbus, &msg_key_params);
+
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(bpy_msgbus_clear_by_owner_doc,
+".. function:: clear_by_owner(owner)\n"
+"\n"
+" Clear all subscribers using this owner.\n"
+);
+static PyObject *bpy_msgbus_clear_by_owner(PyObject *UNUSED(self), PyObject *py_owner)
+{
+ bContext *C = (bContext *)BPy_GetContext();
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ WM_msgbus_clear_by_owner(mbus, py_owner);
+ Py_RETURN_NONE;
+}
+
+static struct PyMethodDef BPy_msgbus_methods[] = {
+ {"subscribe_rna", (PyCFunction)bpy_msgbus_subscribe_rna, METH_VARARGS | METH_KEYWORDS, bpy_msgbus_subscribe_rna_doc},
+ {"publish_rna", (PyCFunction)bpy_msgbus_publish_rna, METH_VARARGS | METH_KEYWORDS, bpy_msgbus_publish_rna_doc},
+ {"clear_by_owner", (PyCFunction)bpy_msgbus_clear_by_owner, METH_O, bpy_msgbus_clear_by_owner_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+static struct PyModuleDef _bpy_msgbus_def = {
+ PyModuleDef_HEAD_INIT,
+ .m_name = "msgbus",
+ .m_methods = BPy_msgbus_methods,
+};
+
+
+PyObject *BPY_msgbus_module(void)
+{
+ PyObject *submodule;
+
+ submodule = PyModule_Create(&_bpy_msgbus_def);
+
+ return submodule;
+}
+
+/** \} */
+
diff --git a/source/blender/python/intern/bpy_msgbus.h b/source/blender/python/intern/bpy_msgbus.h
new file mode 100644
index 00000000000..97b20e9b926
--- /dev/null
+++ b/source/blender/python/intern/bpy_msgbus.h
@@ -0,0 +1,30 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/intern/bpy_msgbus.h
+ * \ingroup pythonintern
+ */
+
+#ifndef __BPY_MSGBUS_H__
+#define __BPY_MSGBUS_H__
+
+PyObject *BPY_msgbus_module(void);
+
+#endif /* __BPY_MSGBUS_H__ */
diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c
index c1fcb0792af..5b84a7cf73c 100644
--- a/source/blender/python/intern/bpy_operator.c
+++ b/source/blender/python/intern/bpy_operator.c
@@ -43,7 +43,7 @@
#include "bpy_operator.h"
#include "bpy_operator_wrap.h"
#include "bpy_rna.h" /* for setting arg props only - pyrna_py_to_prop() */
-#include "bpy_util.h"
+#include "bpy_capi_utils.h"
#include "../generic/bpy_internal_import.h"
#include "../generic/py_capi_utils.h"
#include "../generic/python_utildefines.h"
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index c3d96227dea..d3eddff4b9a 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -37,7 +37,7 @@
#include "bpy_props.h"
#include "bpy_rna.h"
-#include "bpy_util.h"
+#include "bpy_capi_utils.h"
#include "BKE_idprop.h"
@@ -180,22 +180,6 @@ static PyObject *pyrna_struct_as_instance(PointerRNA *ptr)
return self;
}
-/* could be moved into bpy_utils */
-static void printf_func_error(PyObject *py_func)
-{
- /* since we return to C code we can't leave the error */
- PyCodeObject *f_code = (PyCodeObject *)PyFunction_GET_CODE(py_func);
- PyErr_Print();
- PyErr_Clear();
-
- /* use py style error */
- fprintf(stderr, "File \"%s\", line %d, in %s\n",
- _PyUnicode_AsString(f_code->co_filename),
- f_code->co_firstlineno,
- _PyUnicode_AsString(((PyFunctionObject *)py_func)->func_name)
- );
-}
-
static void bpy_prop_assign_flag(PropertyRNA *prop, const int flag)
{
const int flag_mask = ((PROP_ANIMATABLE) & ~flag);
@@ -261,12 +245,12 @@ static void bpy_prop_update_cb(struct bContext *C, struct PointerRNA *ptr, struc
Py_DECREF(args);
if (ret == NULL) {
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
}
else {
if (ret != Py_None) {
PyErr_SetString(PyExc_ValueError, "the return value must be None");
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
}
Py_DECREF(ret);
@@ -313,14 +297,14 @@ static int bpy_prop_boolean_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p
Py_DECREF(args);
if (ret == NULL) {
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
value = false;
}
else {
value = PyC_Long_AsI32(ret);
if (value == -1 && PyErr_Occurred()) {
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
value = false;
}
@@ -372,12 +356,12 @@ static void bpy_prop_boolean_set_cb(struct PointerRNA *ptr, struct PropertyRNA *
Py_DECREF(args);
if (ret == NULL) {
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
}
else {
if (ret != Py_None) {
PyErr_SetString(PyExc_ValueError, "the return value must be None");
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
}
Py_DECREF(ret);
@@ -421,7 +405,7 @@ static int bpy_prop_poll_cb(struct PointerRNA *self, PointerRNA candidate, struc
Py_DECREF(args);
if (ret == NULL) {
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
result = false;
}
else {
@@ -470,14 +454,14 @@ static void bpy_prop_boolean_array_get_cb(struct PointerRNA *ptr, struct Propert
Py_DECREF(args);
if (ret == NULL) {
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
for (i = 0; i < len; ++i)
values[i] = false;
}
else {
if (PyC_AsArray(values, ret, len, &PyBool_Type, false, "BoolVectorProperty get") == -1) {
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
for (i = 0; i < len; ++i)
values[i] = false;
@@ -535,12 +519,12 @@ static void bpy_prop_boolean_array_set_cb(struct PointerRNA *ptr, struct Propert
Py_DECREF(args);
if (ret == NULL) {
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
}
else {
if (ret != Py_None) {
PyErr_SetString(PyExc_ValueError, "the return value must be None");
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
}
Py_DECREF(ret);
@@ -588,14 +572,14 @@ static int bpy_prop_int_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop)
Py_DECREF(args);
if (ret == NULL) {
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
value = 0.0f;
}
else {
value = PyC_Long_AsI32(ret);
if (value == -1 && PyErr_Occurred()) {
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
value = 0;
}
@@ -647,12 +631,12 @@ static void bpy_prop_int_set_cb(struct PointerRNA *ptr, struct PropertyRNA *prop
Py_DECREF(args);
if (ret == NULL) {
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
}
else {
if (ret != Py_None) {
PyErr_SetString(PyExc_ValueError, "the return value must be None");
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
}
Py_DECREF(ret);
@@ -700,14 +684,14 @@ static void bpy_prop_int_array_get_cb(struct PointerRNA *ptr, struct PropertyRNA
Py_DECREF(args);
if (ret == NULL) {
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
for (i = 0; i < len; ++i)
values[i] = 0;
}
else {
if (PyC_AsArray(values, ret, len, &PyLong_Type, false, "IntVectorProperty get") == -1) {
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
for (i = 0; i < len; ++i)
values[i] = 0;
@@ -765,12 +749,12 @@ static void bpy_prop_int_array_set_cb(struct PointerRNA *ptr, struct PropertyRNA
Py_DECREF(args);
if (ret == NULL) {
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
}
else {
if (ret != Py_None) {
PyErr_SetString(PyExc_ValueError, "the return value must be None");
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
}
Py_DECREF(ret);
@@ -818,14 +802,14 @@ static float bpy_prop_float_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p
Py_DECREF(args);
if (ret == NULL) {
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
value = 0.0f;
}
else {
value = PyFloat_AsDouble(ret);
if (value == -1.0f && PyErr_Occurred()) {
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
value = 0.0f;
}
@@ -877,12 +861,12 @@ static void bpy_prop_float_set_cb(struct PointerRNA *ptr, struct PropertyRNA *pr
Py_DECREF(args);
if (ret == NULL) {
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
}
else {
if (ret != Py_None) {
PyErr_SetString(PyExc_ValueError, "the return value must be None");
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
}
Py_DECREF(ret);
@@ -930,14 +914,14 @@ static void bpy_prop_float_array_get_cb(struct PointerRNA *ptr, struct PropertyR
Py_DECREF(args);
if (ret == NULL) {
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
for (i = 0; i < len; ++i)
values[i] = 0.0f;
}
else {
if (PyC_AsArray(values, ret, len, &PyFloat_Type, false, "FloatVectorProperty get") == -1) {
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
for (i = 0; i < len; ++i)
values[i] = 0.0f;
@@ -995,12 +979,12 @@ static void bpy_prop_float_array_set_cb(struct PointerRNA *ptr, struct PropertyR
Py_DECREF(args);
if (ret == NULL) {
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
}
else {
if (ret != Py_None) {
PyErr_SetString(PyExc_ValueError, "the return value must be None");
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
}
Py_DECREF(ret);
@@ -1047,14 +1031,14 @@ static void bpy_prop_string_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p
Py_DECREF(args);
if (ret == NULL) {
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
value[0] = '\0';
}
else if (!PyUnicode_Check(ret)) {
PyErr_Format(PyExc_TypeError,
"return value must be a string, not %.200s",
Py_TYPE(ret)->tp_name);
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
value[0] = '\0';
Py_DECREF(ret);
}
@@ -1107,14 +1091,14 @@ static int bpy_prop_string_length_cb(struct PointerRNA *ptr, struct PropertyRNA
Py_DECREF(args);
if (ret == NULL) {
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
length = 0;
}
else if (!PyUnicode_Check(ret)) {
PyErr_Format(PyExc_TypeError,
"return value must be a string, not %.200s",
Py_TYPE(ret)->tp_name);
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
length = 0;
Py_DECREF(ret);
}
@@ -1167,7 +1151,7 @@ static void bpy_prop_string_set_cb(struct PointerRNA *ptr, struct PropertyRNA *p
py_value = PyUnicode_FromString(value);
if (!py_value) {
PyErr_SetString(PyExc_ValueError, "the return value must be a string");
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
}
else
PyTuple_SET_ITEM(args, 1, py_value);
@@ -1177,12 +1161,12 @@ static void bpy_prop_string_set_cb(struct PointerRNA *ptr, struct PropertyRNA *p
Py_DECREF(args);
if (ret == NULL) {
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
}
else {
if (ret != Py_None) {
PyErr_SetString(PyExc_ValueError, "the return value must be None");
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
}
Py_DECREF(ret);
@@ -1230,14 +1214,14 @@ static int bpy_prop_enum_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop
Py_DECREF(args);
if (ret == NULL) {
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
value = RNA_property_enum_get_default(ptr, prop);
}
else {
value = PyC_Long_AsI32(ret);
if (value == -1 && PyErr_Occurred()) {
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
value = RNA_property_enum_get_default(ptr, prop);
}
@@ -1289,12 +1273,12 @@ static void bpy_prop_enum_set_cb(struct PointerRNA *ptr, struct PropertyRNA *pro
Py_DECREF(args);
if (ret == NULL) {
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
}
else {
if (ret != Py_None) {
PyErr_SetString(PyExc_ValueError, "the return value must be None");
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
}
Py_DECREF(ret);
@@ -1572,7 +1556,7 @@ static const EnumPropertyItem *bpy_prop_enum_itemf_cb(struct bContext *C, Pointe
*r_free = true;
}
else {
- printf_func_error(py_func);
+ PyC_Err_PrintWithFunc(py_func);
eitems = DummyRNA_NULL_items;
}
diff --git a/source/blender/python/intern/bpy_props.h b/source/blender/python/intern/bpy_props.h
index 614c1b4b708..fa2594f94d2 100644
--- a/source/blender/python/intern/bpy_props.h
+++ b/source/blender/python/intern/bpy_props.h
@@ -34,6 +34,6 @@ PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw);
PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw);
StructRNA *pointer_type_from_py(PyObject *value, const char *error_prefix);
-#define PYRNA_STACK_ARRAY 32
+#define PYRNA_STACK_ARRAY RNA_STACK_ARRAY
#endif
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 9630beb6e8b..fdad3a7d919 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -49,7 +49,7 @@
#include "bpy_rna.h"
#include "bpy_rna_anim.h"
#include "bpy_props.h"
-#include "bpy_util.h"
+#include "bpy_capi_utils.h"
#include "bpy_rna_callback.h"
#include "bpy_intern_string.h"
diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c
index 8a0130babd5..9f9bb46c8bb 100644
--- a/source/blender/python/intern/bpy_rna_anim.c
+++ b/source/blender/python/intern/bpy_rna_anim.c
@@ -53,7 +53,7 @@
#include "WM_types.h"
#include "bpy_rna.h"
-#include "bpy_util.h"
+#include "bpy_capi_utils.h"
#include "bpy_rna_anim.h"
#include "../generic/python_utildefines.h"
diff --git a/source/blender/python/intern/bpy_rna_callback.c b/source/blender/python/intern/bpy_rna_callback.c
index fe3565fc44e..68783feacd9 100644
--- a/source/blender/python/intern/bpy_rna_callback.c
+++ b/source/blender/python/intern/bpy_rna_callback.c
@@ -36,7 +36,7 @@
#include "bpy_rna.h"
#include "bpy_rna_callback.h"
-#include "bpy_util.h"
+#include "bpy_capi_utils.h"
#include "DNA_space_types.h"
#include "DNA_screen_types.h"
diff --git a/source/blender/python/intern/bpy_rna_id_collection.c b/source/blender/python/intern/bpy_rna_id_collection.c
index 8def52dc8fb..ee40d30d73b 100644
--- a/source/blender/python/intern/bpy_rna_id_collection.c
+++ b/source/blender/python/intern/bpy_rna_id_collection.c
@@ -44,7 +44,7 @@
#include "DNA_object_types.h"
#include "DNA_key_types.h"
-#include "bpy_util.h"
+#include "bpy_capi_utils.h"
#include "bpy_rna_id_collection.h"
#include "../generic/py_capi_utils.h"
diff --git a/source/blender/python/intern/bpy_rna_manipulator.c b/source/blender/python/intern/bpy_rna_manipulator.c
index 4a326ae657b..950f7f98be0 100644
--- a/source/blender/python/intern/bpy_rna_manipulator.c
+++ b/source/blender/python/intern/bpy_rna_manipulator.c
@@ -37,7 +37,7 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "bpy_util.h"
+#include "bpy_capi_utils.h"
#include "bpy_rna_manipulator.h"
#include "../generic/py_capi_utils.h"
diff --git a/source/blender/python/mathutils/mathutils.h b/source/blender/python/mathutils/mathutils.h
index d1fb6dcdb82..ec927a9e316 100644
--- a/source/blender/python/mathutils/mathutils.h
+++ b/source/blender/python/mathutils/mathutils.h
@@ -78,6 +78,10 @@ typedef struct {
#include "mathutils_Euler.h"
#include "mathutils_Color.h"
+/* avoid checking all types */
+#define BaseMathObject_CheckExact(v) \
+ (Py_TYPE(v)->tp_dealloc == (destructor)BaseMathObject_dealloc)
+
PyObject *BaseMathObject_owner_get(BaseMathObject *self, void *);
PyObject *BaseMathObject_is_wrapped_get(BaseMathObject *self, void *);
PyObject *BaseMathObject_is_frozen_get(BaseMathObject *self, void *);
diff --git a/source/blender/python/mathutils/mathutils_Color.h b/source/blender/python/mathutils/mathutils_Color.h
index 1290f73da62..e1a392de3da 100644
--- a/source/blender/python/mathutils/mathutils_Color.h
+++ b/source/blender/python/mathutils/mathutils_Color.h
@@ -30,7 +30,8 @@
#define __MATHUTILS_COLOR_H__
extern PyTypeObject color_Type;
-#define ColorObject_Check(_v) PyObject_TypeCheck((_v), &color_Type)
+#define ColorObject_Check(v) PyObject_TypeCheck((v), &color_Type)
+#define ColorObject_CheckExact(v) (Py_TYPE(v) == &color_Type)
typedef struct {
BASE_MATH_MEMBERS(col);
diff --git a/source/blender/python/mathutils/mathutils_Euler.h b/source/blender/python/mathutils/mathutils_Euler.h
index 744f39faed1..4f5ba76b8df 100644
--- a/source/blender/python/mathutils/mathutils_Euler.h
+++ b/source/blender/python/mathutils/mathutils_Euler.h
@@ -29,7 +29,8 @@
*/
extern PyTypeObject euler_Type;
-#define EulerObject_Check(_v) PyObject_TypeCheck((_v), &euler_Type)
+#define EulerObject_Check(v) PyObject_TypeCheck((v), &euler_Type)
+#define EulerObject_CheckExact(v) (Py_TYPE(v) == &euler_Type)
typedef struct {
BASE_MATH_MEMBERS(eul);
diff --git a/source/blender/python/mathutils/mathutils_Matrix.h b/source/blender/python/mathutils/mathutils_Matrix.h
index 9c84716d307..d2fbe6a04d5 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.h
+++ b/source/blender/python/mathutils/mathutils_Matrix.h
@@ -30,7 +30,10 @@
extern PyTypeObject matrix_Type;
extern PyTypeObject matrix_access_Type;
-#define MatrixObject_Check(_v) PyObject_TypeCheck((_v), &matrix_Type)
+
+#define MatrixObject_Check(v) PyObject_TypeCheck((v), &matrix_Type)
+#define MatrixObject_CheckExact(v) (Py_TYPE(v) == &matrix_Type)
+
#define MATRIX_MAX_DIM 4
/* matrix[row][col] == MATRIX_ITEM_INDEX(matrix, row, col) */
diff --git a/source/blender/python/mathutils/mathutils_Quaternion.h b/source/blender/python/mathutils/mathutils_Quaternion.h
index 66ee3362906..46f305b0f0e 100644
--- a/source/blender/python/mathutils/mathutils_Quaternion.h
+++ b/source/blender/python/mathutils/mathutils_Quaternion.h
@@ -28,7 +28,9 @@
*/
extern PyTypeObject quaternion_Type;
-#define QuaternionObject_Check(_v) PyObject_TypeCheck((_v), &quaternion_Type)
+
+#define QuaternionObject_Check(v) PyObject_TypeCheck((v), &quaternion_Type)
+#define QuaternionObject_CheckExact(v) (Py_TYPE(v) == &quaternion_Type)
typedef struct {
BASE_MATH_MEMBERS(quat);
diff --git a/source/blender/python/mathutils/mathutils_Vector.h b/source/blender/python/mathutils/mathutils_Vector.h
index 74ca3336f4b..9ebf9457f2b 100644
--- a/source/blender/python/mathutils/mathutils_Vector.h
+++ b/source/blender/python/mathutils/mathutils_Vector.h
@@ -29,7 +29,9 @@
#define __MATHUTILS_VECTOR_H__
extern PyTypeObject vector_Type;
-#define VectorObject_Check(_v) PyObject_TypeCheck((_v), &vector_Type)
+
+#define VectorObject_Check(v) PyObject_TypeCheck((v), &vector_Type)
+#define VectorObject_CheckExact(v) (Py_TYPE(v) == &vector_Type)
typedef struct {
BASE_MATH_MEMBERS(vec);
diff --git a/source/blender/python/mathutils/mathutils_bvhtree.h b/source/blender/python/mathutils/mathutils_bvhtree.h
index 634556d68f7..445a393b93e 100644
--- a/source/blender/python/mathutils/mathutils_bvhtree.h
+++ b/source/blender/python/mathutils/mathutils_bvhtree.h
@@ -30,7 +30,7 @@ PyMODINIT_FUNC PyInit_mathutils_bvhtree(void);
extern PyTypeObject PyBVHTree_Type;
-#define PyBVHTree_Check(_v) PyObject_TypeCheck((_v), &PyBVHTree_Type)
+#define PyBVHTree_Check(v) PyObject_TypeCheck((v), &PyBVHTree_Type)
#define PyBVHTree_CheckExact(v) (Py_TYPE(v) == &PyBVHTree_Type)
#endif /* __MATHUTILS_BVHTREE_H__ */
diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
index 81ed4c71b17..74de3fcded6 100644
--- a/source/blender/render/intern/source/convertblender.c
+++ b/source/blender/render/intern/source/convertblender.c
@@ -68,6 +68,7 @@
#include "BKE_displist.h"
#include "BKE_DerivedMesh.h"
#include "BKE_global.h"
+#include "BKE_group.h"
#include "BKE_key.h"
#include "BKE_image.h"
#include "BKE_lattice.h"
@@ -3979,28 +3980,32 @@ static bool is_object_hidden(Render *re, Object *ob)
/* layflag: allows material group to ignore layerflag */
static void add_lightgroup(Render *re, Group *group, int exclusive)
{
- GroupObject *go, *gol;
-
group->id.tag &= ~LIB_TAG_DOIT;
+#if 0
/* it's a bit too many loops in loops... but will survive */
/* note that 'exclusive' will remove it from the global list */
- for (go= group->gobject.first; go; go= go->next) {
- go->lampren= NULL;
+ FOREACH_GROUP_BASE(group, base)
+ {
+ Object *object = base->object;
- if (is_object_hidden(re, go->ob))
+ if (is_object_hidden(re, object)) {
continue;
-
- if (go->ob->lay & re->lay) {
- if (go->ob && go->ob->type==OB_LAMP) {
- for (gol= re->lights.first; gol; gol= gol->next) {
- if (gol->ob==go->ob) {
- go->lampren= gol->lampren;
+ }
+
+ if (base->flag & BASE_VISIBLED) {
+ if (object && object->type == OB_LAMP) {
+ for (GroupObject *gol = re->lights.first; gol; gol = gol->next) {
+ if (gol->ob == object) {
+ go->lampren = gol->lampren;
break;
}
}
- if (go->lampren==NULL)
- gol= add_render_lamp(re, go->ob);
+
+ if (go->lampren == NULL) {
+ gol= add_render_lamp(re, object);
+ }
+
if (gol && exclusive) {
BLI_remlink(&re->lights, gol);
MEM_freeN(gol);
@@ -4008,6 +4013,10 @@ static void add_lightgroup(Render *re, Group *group, int exclusive)
}
}
}
+ FOREACH_GROUP_BASE_END
+#else
+ UNUSED_VARS(re, exclusive);
+#endif
}
static void set_material_lightgroups(Render *re)
@@ -4899,8 +4908,6 @@ static void dupli_render_particle_set(Render *re, Object *ob, int timeoffset, in
{
/* ugly function, but we need to set particle systems to their render
* settings before calling object_duplilist, to get render level duplis */
- Group *group;
- GroupObject *go;
ParticleSystem *psys;
DerivedMesh *dm;
@@ -4932,11 +4939,13 @@ static void dupli_render_particle_set(Render *re, Object *ob, int timeoffset, in
}
}
- if (ob->dup_group==NULL) return;
- group= ob->dup_group;
+ if (ob->dup_group == NULL) return;
- for (go= group->gobject.first; go; go= go->next)
- dupli_render_particle_set(re, go->ob, timeoffset, level+1, enable);
+ FOREACH_GROUP_OBJECT(ob->dup_group, object)
+ {
+ dupli_render_particle_set(re, object, timeoffset, level+1, enable);
+ }
+ FOREACH_GROUP_OBJECT_END
}
static int get_vector_viewlayers(Scene *UNUSED(sce))
@@ -4946,29 +4955,27 @@ static int get_vector_viewlayers(Scene *UNUSED(sce))
static void add_group_render_dupli_obs(Render *re, Group *group, int nolamps, int onlyselected, Object *actob, int timeoffset, int level)
{
- GroupObject *go;
- Object *ob;
-
- /* simple preventing of too deep nested groups */
- if (level>MAX_DUPLI_RECUR) return;
-
- /* recursively go into dupligroups to find objects with OB_RENDER_DUPLI
- * that were not created yet */
- for (go= group->gobject.first; go; go= go->next) {
- ob= go->ob;
+ /* Simple preventing of too deep nested groups. */
+ if (level > MAX_DUPLI_RECUR) return;
+ /* Recursively go into dupligroups to find objects with OB_RENDER_DUPLI
+ * that were not created yet. */
+ FOREACH_GROUP_OBJECT(group, ob)
+ {
if (ob->flag & OB_DONE) {
if (ob->transflag & OB_RENDER_DUPLI) {
if (allow_render_object(re, ob, nolamps, onlyselected, actob)) {
init_render_object(re, ob, NULL, NULL, NULL, timeoffset);
ob->transflag &= ~OB_RENDER_DUPLI;
- if (ob->dup_group)
+ if (ob->dup_group) {
add_group_render_dupli_obs(re, ob->dup_group, nolamps, onlyselected, actob, timeoffset, level+1);
+ }
}
}
}
}
+ FOREACH_GROUP_OBJECT_END
}
static void database_init_objects(Render *re, unsigned int UNUSED(renderlay), int nolamps, int onlyselected, Object *actob, int timeoffset)
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt
index 95a0371ba23..b5784fe543c 100644
--- a/source/blender/windowmanager/CMakeLists.txt
+++ b/source/blender/windowmanager/CMakeLists.txt
@@ -79,6 +79,9 @@ set(SRC
manipulators/intern/wm_manipulator_map.c
manipulators/intern/wm_manipulator_target_props.c
manipulators/intern/wm_manipulator_type.c
+ message_bus/intern/wm_message_bus.c
+ message_bus/intern/wm_message_bus_rna.c
+ message_bus/intern/wm_message_bus_static.c
WM_api.h
WM_keymap.h
@@ -96,6 +99,8 @@ set(SRC
manipulators/wm_manipulator_fn.h
manipulators/wm_manipulator_wmapi.h
manipulators/intern/wm_manipulator_intern.h
+ message_bus/intern/wm_message_bus_intern.h
+ message_bus/wm_message_bus.h
)
if(WITH_AUDASPACE)
diff --git a/source/blender/windowmanager/WM_message.h b/source/blender/windowmanager/WM_message.h
new file mode 100644
index 00000000000..48197ae99cd
--- /dev/null
+++ b/source/blender/windowmanager/WM_message.h
@@ -0,0 +1,30 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/WM_message.h
+ * \ingroup wm
+ */
+
+#ifndef __WM_MESSAGE_H__
+#define __WM_MESSAGE_H__
+
+#include "message_bus/wm_message_bus.h"
+
+#endif /* __WM_MESSAGE_H__ */
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 6e43d9715f1..27f872fc2bb 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -109,6 +109,7 @@ extern "C" {
struct bContext;
struct wmEvent;
struct wmWindowManager;
+struct wmMsgBus;
struct wmOperator;
struct ImBuf;
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c
index 5d2bce791da..47fcbb1f523 100644
--- a/source/blender/windowmanager/intern/wm.c
+++ b/source/blender/windowmanager/intern/wm.c
@@ -56,6 +56,7 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
#include "wm_window.h"
#include "wm_event_system.h"
#include "wm_draw.h"
@@ -399,6 +400,10 @@ void WM_check(bContext *C)
wm_window_ghostwindows_ensure(wm);
}
+ if (wm->message_bus == NULL) {
+ wm->message_bus = WM_msgbus_create();
+ }
+
/* case: fileread */
/* note: this runs in bg mode to set the screen context cb */
if ((wm->initialized & WM_WINDOW_IS_INITIALIZED) == 0) {
@@ -479,7 +484,11 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm)
}
BLI_freelistN(&wm->queue);
-
+
+ if (wm->message_bus != NULL) {
+ WM_msgbus_destroy(wm->message_bus);
+ }
+
BLI_freelistN(&wm->paintcursors);
WM_drag_free_list(&wm->drags);
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 4220b8b4d62..02cf9981a3a 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -39,7 +39,6 @@
#include "DNA_screen_types.h"
#include "DNA_scene_types.h"
#include "DNA_windowmanager_types.h"
-#include "DNA_workspace_types.h"
#include "DNA_userdef_types.h"
#include "MEM_guardedalloc.h"
@@ -77,6 +76,7 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
#include "wm.h"
#include "wm_window.h"
#include "wm_event_system.h"
@@ -242,6 +242,14 @@ void WM_main_remove_notifier_reference(const void *reference)
wm_notifier_clear(note);
}
}
+
+ /* Remap instead. */
+#if 0
+ if (wm->message_bus) {
+ WM_msg_id_remove(wm->message_bus, reference);
+ }
+#endif
+
}
}
@@ -261,6 +269,17 @@ void WM_main_remap_editor_id_reference(ID *old_id, ID *new_id)
}
}
}
+
+ wmWindowManager *wm = bmain->wm.first;
+ if (wm && wm->message_bus) {
+ struct wmMsgBus *mbus = wm->message_bus;
+ if (new_id != NULL) {
+ WM_msg_id_update(mbus, old_id, new_id);
+ }
+ else {
+ WM_msg_id_remove(mbus, old_id);
+ }
+ }
}
static void wm_notifier_clear(wmNotifier *note)
@@ -328,7 +347,9 @@ void wm_event_do_notifiers(bContext *C)
if (wm == NULL)
return;
-
+
+ /* disable? - keep for now since its used for window level notifiers. */
+#if 1
/* cache & catch WM level notifiers, such as frame change, scene/screen set */
for (win = wm->windows.first; win; win = win->next) {
Scene *scene = WM_window_get_active_scene(win);
@@ -458,6 +479,16 @@ void wm_event_do_notifiers(bContext *C)
MEM_freeN(note);
}
+#endif /* if 1 (postpone disabling for in favor of message-bus), eventually. */
+
+ /* Handle message bus. */
+ {
+ for (win = wm->windows.first; win; win = win->next) {
+ CTX_wm_window_set(C, win);
+ WM_msgbus_handle(wm->message_bus, C);
+ }
+ CTX_wm_window_set(C, NULL);
+ }
wm_event_do_refresh_wm_and_depsgraph(C);
}
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index c3ae4af1964..7c8059fcda9 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -123,6 +123,7 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
#include "wm.h"
#include "wm_files.h"
#include "wm_window.h"
@@ -504,7 +505,11 @@ static void wm_file_read_post(bContext *C, const bool is_startup_file, const boo
BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_VERSION_UPDATE);
BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST);
+#if 1
WM_event_add_notifier(C, NC_WM | ND_FILEREAD, NULL);
+#else
+ WM_msg_publish_static(CTX_wm_message_bus(C), WM_MSG_STATICTYPE_FILE_READ);
+#endif
/* report any errors.
* currently disabled if addons aren't yet loaded */
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
index 2086ade99d2..cd6a38cb9a8 100644
--- a/source/blender/windowmanager/intern/wm_files_link.c
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -159,7 +159,7 @@ typedef struct WMLinkAppendData {
LinkNodePair items;
int num_libraries;
int num_items;
- short flag;
+ int flag; /* Combines eFileSel_Params_Flag from DNA_space_types.h and BLO_LibLinkFlags from BLO_readfile.h */
/* Internal 'private' data */
MemArena *memarena;
@@ -214,8 +214,7 @@ static WMLinkAppendDataItem *wm_link_append_data_item_add(
}
static void wm_link_do(
- WMLinkAppendData *lapp_data, ReportList *reports, Main *bmain, Scene *scene, ViewLayer *view_layer,
- const bool use_placeholders, const bool force_indirect)
+ WMLinkAppendData *lapp_data, ReportList *reports, Main *bmain, Scene *scene, ViewLayer *view_layer)
{
Main *mainl;
BlendHandle *bh;
@@ -262,8 +261,7 @@ static void wm_link_do(
continue;
}
- new_id = BLO_library_link_named_part_ex(
- mainl, &bh, item->idcode, item->name, flag, scene, view_layer, use_placeholders, force_indirect);
+ new_id = BLO_library_link_named_part_ex(mainl, &bh, item->idcode, item->name, flag, scene, view_layer);
if (new_id) {
/* If the link is successful, clear item's libs 'todo' flags.
@@ -372,6 +370,8 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
scene = NULL;
}
+ /* We need to add nothing from BLO_LibLinkFlags to flag here. */
+
/* from here down, no error returns */
if (view_layer && RNA_boolean_get(op->ptr, "autoselect")) {
@@ -453,7 +453,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
/* XXX We'd need re-entrant locking on Main for this to work... */
/* BKE_main_lock(bmain); */
- wm_link_do(lapp_data, op->reports, bmain, scene, view_layer, false, false);
+ wm_link_do(lapp_data, op->reports, bmain, scene, view_layer);
/* BKE_main_unlock(bmain); */
@@ -653,7 +653,7 @@ static void lib_relocate_do(
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
/* We do not want any instanciation here! */
- wm_link_do(lapp_data, reports, bmain, NULL, NULL, do_reload, do_reload);
+ wm_link_do(lapp_data, reports, bmain, NULL, NULL);
BKE_main_lock(bmain);
@@ -814,7 +814,7 @@ void WM_lib_reload(Library *lib, bContext *C, ReportList *reports)
return;
}
- WMLinkAppendData *lapp_data = wm_link_append_data_new(0);
+ WMLinkAppendData *lapp_data = wm_link_append_data_new(BLO_LIBLINK_USE_PLACEHOLDERS | BLO_LIBLINK_FORCE_INDIRECT);
wm_link_append_data_library_add(lapp_data, lib->filepath);
@@ -924,6 +924,10 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload)
}
}
+ if (do_reload) {
+ lapp_data->flag |= BLO_LIBLINK_USE_PLACEHOLDERS | BLO_LIBLINK_FORCE_INDIRECT;
+ }
+
lib_relocate_do(bmain, lib, lapp_data, op->reports, do_reload);
wm_link_append_data_free(lapp_data);
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index fc1805e102f..55ed8b2a091 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -93,6 +93,7 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
#include "wm_cursors.h"
#include "wm_event_system.h"
@@ -178,8 +179,7 @@ void WM_init(bContext *C, int argc, const char **argv)
BKE_blender_callback_test_break_set(wm_window_testbreak); /* blender.c */
BKE_spacedata_callback_id_remap_set(ED_spacedata_id_remap); /* screen.c */
DEG_editors_set_update_cb(ED_render_id_flush_update,
- ED_render_scene_update,
- ED_render_scene_update_pre);
+ ED_render_scene_update);
ED_spacetypes_init(); /* editors/space_api/spacetype.c */
@@ -193,6 +193,8 @@ void WM_init(bContext *C, int argc, const char **argv)
* but keep before file reading, since that may report errors */
wm_init_reports(C);
+ WM_msgbus_types_init();
+
/* get the default database, plus a wm */
wm_homefile_read(C, NULL, G.factory_startup, false, true, NULL, NULL);
diff --git a/source/blender/windowmanager/manipulators/WM_manipulator_api.h b/source/blender/windowmanager/manipulators/WM_manipulator_api.h
index a3875c50348..9214bccb6a0 100644
--- a/source/blender/windowmanager/manipulators/WM_manipulator_api.h
+++ b/source/blender/windowmanager/manipulators/WM_manipulator_api.h
@@ -51,6 +51,8 @@ struct wmManipulatorGroupType;
struct wmManipulatorMap;
struct wmManipulatorMapType;
struct wmManipulatorMapType_Params;
+struct wmMsgSubscribeKey;
+struct wmMsgSubscribeValue;
#include "wm_manipulator_fn.h"
@@ -216,6 +218,11 @@ const struct wmManipulatorPropertyType *WM_manipulatortype_target_property_find(
void WM_manipulatortype_target_property_def(
struct wmManipulatorType *wt, const char *idname, int data_type, int array_length);
+/* utilities */
+void WM_manipulator_do_msg_notify_tag_refresh(
+ struct bContext *C, struct wmMsgSubscribeKey *msg_key, struct wmMsgSubscribeValue *msg_val);
+void WM_manipulator_target_property_subscribe_all(
+ struct wmManipulator *mpr, struct wmMsgBus *mbus, struct ARegion *ar);
/* -------------------------------------------------------------------- */
/* wmManipulatorGroup */
@@ -245,6 +252,8 @@ void WM_manipulatormap_draw(
void WM_manipulatormap_add_handlers(struct ARegion *ar, struct wmManipulatorMap *mmap);
bool WM_manipulatormap_select_all(struct bContext *C, struct wmManipulatorMap *mmap, const int action);
bool WM_manipulatormap_cursor_set(const struct wmManipulatorMap *mmap, struct wmWindow *win);
+void WM_manipulatormap_message_subscribe(
+ struct bContext *C, struct wmManipulatorMap *mmap, struct ARegion *ar, struct wmMsgBus *mbus);
bool WM_manipulatormap_is_any_selected(const struct wmManipulatorMap *mmap);
bool WM_manipulatormap_minmax(
const struct wmManipulatorMap *mmap, bool use_hidden, bool use_select,
diff --git a/source/blender/windowmanager/manipulators/WM_manipulator_types.h b/source/blender/windowmanager/manipulators/WM_manipulator_types.h
index d4477b8e508..5fa89b8d35f 100644
--- a/source/blender/windowmanager/manipulators/WM_manipulator_types.h
+++ b/source/blender/windowmanager/manipulators/WM_manipulator_types.h
@@ -346,6 +346,11 @@ typedef struct wmManipulatorGroupType {
* will fall back to default tweak keymap when left NULL. */
wmManipulatorGroupFnSetupKeymap setup_keymap;
+ /* Optionally subscribe to wmMsgBus events,
+ * these are calculated automatically from RNA properties,
+ * only needed if manipulators depend indirectly on properties. */
+ wmManipulatorGroupFnMsgBusSubscribe message_subscribe;
+
/* keymap created with callback from above */
struct wmKeyMap *keymap;
/* Only for convenient removal. */
diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c b/source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c
index a174d7720e3..5d9810272cc 100644
--- a/source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c
+++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator_map.c
@@ -305,6 +305,7 @@ static bool manipulator_prepare_drawing(
/* skip */
}
else {
+ /* Ensure we get RNA updates */
if (do_draw & WM_MANIPULATOR_IS_VISIBLE_UPDATE) {
/* hover manipulators need updating, even if we don't draw them */
wm_manipulator_update(mpr, C, (mmap->update_flag[drawstep] & MANIPULATORMAP_IS_PREPARE_DRAW) != 0);
@@ -953,6 +954,25 @@ ListBase *wm_manipulatormap_groups_get(wmManipulatorMap *mmap)
return &mmap->groups;
}
+void WM_manipulatormap_message_subscribe(
+ bContext *C, wmManipulatorMap *mmap, ARegion *ar, struct wmMsgBus *mbus)
+{
+ for (wmManipulatorGroup *mgroup = mmap->groups.first; mgroup; mgroup = mgroup->next) {
+ if (!wm_manipulatorgroup_is_visible(mgroup, C)) {
+ continue;
+ }
+ for (wmManipulator *mpr = mgroup->manipulators.first; mpr; mpr = mpr->next) {
+ if (mpr->flag & WM_MANIPULATOR_HIDDEN) {
+ continue;
+ }
+ WM_manipulator_target_property_subscribe_all(mpr, mbus, ar);
+ }
+ if (mgroup->type->message_subscribe != NULL) {
+ mgroup->type->message_subscribe(C, mgroup, mbus);
+ }
+ }
+}
+
/** \} */ /* wmManipulatorMap */
diff --git a/source/blender/windowmanager/manipulators/intern/wm_manipulator_target_props.c b/source/blender/windowmanager/manipulators/intern/wm_manipulator_target_props.c
index 836376f1c54..137e8f5639d 100644
--- a/source/blender/windowmanager/manipulators/intern/wm_manipulator_target_props.c
+++ b/source/blender/windowmanager/manipulators/intern/wm_manipulator_target_props.c
@@ -35,6 +35,7 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
#include "wm.h"
@@ -311,3 +312,53 @@ void WM_manipulatortype_target_property_def(
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Property Utilities
+ * \{ */
+
+void WM_manipulator_do_msg_notify_tag_refresh(
+ bContext *UNUSED(C), wmMsgSubscribeKey *UNUSED(msg_key), wmMsgSubscribeValue *msg_val)
+{
+ ARegion *ar = msg_val->owner;
+ wmManipulatorMap *mmap = msg_val->user_data;
+
+ ED_region_tag_redraw(ar);
+ WM_manipulatormap_tag_refresh(mmap);
+}
+
+/**
+ * Runs on the "prepare draw" pass,
+ * drawing the region clears.
+ */
+void WM_manipulator_target_property_subscribe_all(
+ wmManipulator *mpr, struct wmMsgBus *mbus, ARegion *ar)
+{
+ if (mpr->type->target_property_defs_len) {
+ wmManipulatorProperty *mpr_prop_array = WM_manipulator_target_property_array(mpr);
+ for (int i = 0; i < mpr->type->target_property_defs_len; i++) {
+ wmManipulatorProperty *mpr_prop = &mpr_prop_array[i];
+ if (WM_manipulator_target_property_is_valid(mpr_prop)) {
+ if (mpr_prop->prop) {
+ WM_msg_subscribe_rna(
+ mbus, &mpr_prop->ptr, mpr_prop->prop,
+ &(const wmMsgSubscribeValue){
+ .owner = ar,
+ .user_data = ar,
+ .notify = ED_region_do_msg_notify_tag_redraw,
+ }, __func__);
+ WM_msg_subscribe_rna(
+ mbus, &mpr_prop->ptr, mpr_prop->prop,
+ &(const wmMsgSubscribeValue){
+ .owner = ar,
+ .user_data = mpr->parent_mgroup->parent_mmap,
+ .notify = WM_manipulator_do_msg_notify_tag_refresh,
+ }, __func__);
+ }
+ }
+ }
+ }
+}
+
+/** \} */
diff --git a/source/blender/windowmanager/manipulators/wm_manipulator_fn.h b/source/blender/windowmanager/manipulators/wm_manipulator_fn.h
index c54024529c3..7e163f8a785 100644
--- a/source/blender/windowmanager/manipulators/wm_manipulator_fn.h
+++ b/source/blender/windowmanager/manipulators/wm_manipulator_fn.h
@@ -42,6 +42,8 @@ typedef void (*wmManipulatorGroupFnDrawPrepare)(
typedef struct wmKeyMap *(*wmManipulatorGroupFnSetupKeymap)(
const struct wmManipulatorGroupType *, struct wmKeyConfig *)
ATTR_WARN_UNUSED_RESULT;
+typedef void (*wmManipulatorGroupFnMsgBusSubscribe)(
+ const struct bContext *, struct wmManipulatorGroup *, struct wmMsgBus *);
/* wmManipulator */
/* See: wmManipulatorType for docs on each type. */
diff --git a/source/blender/windowmanager/message_bus/intern/wm_message_bus.c b/source/blender/windowmanager/message_bus/intern/wm_message_bus.c
new file mode 100644
index 00000000000..7183655b0de
--- /dev/null
+++ b/source/blender/windowmanager/message_bus/intern/wm_message_bus.c
@@ -0,0 +1,247 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/message_bus/intern/wm_message_bus.c
+ * \ingroup wm
+ */
+
+#include <string.h>
+
+#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
+
+#include "BLI_ghash.h"
+
+#include "WM_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "message_bus/wm_message_bus.h"
+#include "message_bus/intern/wm_message_bus_intern.h"
+
+/* -------------------------------------------------------------------------- */
+/** \name Public API
+ * \{ */
+
+static wmMsgTypeInfo wm_msg_types[WM_MSG_TYPE_NUM] = {NULL};
+
+typedef void (*wmMsgTypeInitFn)(wmMsgTypeInfo *);
+
+static wmMsgTypeInitFn wm_msg_init_fn[WM_MSG_TYPE_NUM] = {
+ WM_msgtypeinfo_init_rna,
+ WM_msgtypeinfo_init_static,
+};
+
+void WM_msgbus_types_init(void)
+{
+ for (uint i = 0; i < WM_MSG_TYPE_NUM; i++) {
+ wm_msg_init_fn[i](&wm_msg_types[i]);
+ }
+}
+
+struct wmMsgBus *WM_msgbus_create(void)
+{
+ struct wmMsgBus *mbus = MEM_callocN(sizeof(*mbus), __func__);
+ const uint gset_reserve = 512;
+ for (uint i = 0; i < WM_MSG_TYPE_NUM; i++) {
+ wmMsgTypeInfo *info = &wm_msg_types[i];
+ mbus->messages_gset[i] = BLI_gset_new_ex(info->gset.hash_fn, info->gset.cmp_fn, __func__, gset_reserve);
+ }
+ return mbus;
+}
+
+void WM_msgbus_destroy(struct wmMsgBus *mbus)
+{
+ for (uint i = 0; i < WM_MSG_TYPE_NUM; i++) {
+ wmMsgTypeInfo *info = &wm_msg_types[i];
+ BLI_gset_free(mbus->messages_gset[i], info->gset.key_free_fn);
+ }
+ MEM_freeN(mbus);
+}
+
+void WM_msgbus_clear_by_owner(struct wmMsgBus *mbus, void *owner)
+{
+ wmMsgSubscribeKey *msg_key, *msg_key_next;
+ for (msg_key = mbus->messages.first; msg_key; msg_key = msg_key_next) {
+ msg_key_next = msg_key->next;
+
+ wmMsgSubscribeValueLink *msg_lnk_next;
+ for (wmMsgSubscribeValueLink *msg_lnk = msg_key->values.first; msg_lnk; msg_lnk = msg_lnk_next) {
+ msg_lnk_next = msg_lnk->next;
+ if (msg_lnk->params.owner == owner) {
+ if (msg_lnk->params.free_data) {
+ msg_lnk->params.free_data(msg_key, &msg_lnk->params);
+ }
+ BLI_remlink(&msg_key->values, msg_lnk);
+ MEM_freeN(msg_lnk);
+ }
+ }
+
+ if (BLI_listbase_is_empty(&msg_key->values)) {
+ const wmMsg *msg = wm_msg_subscribe_value_msg_cast(msg_key);
+ wmMsgTypeInfo *info = &wm_msg_types[msg->type];
+ BLI_remlink(&mbus->messages, msg_key);
+ bool ok = BLI_gset_remove(mbus->messages_gset[msg->type], msg_key, info->gset.key_free_fn);
+ BLI_assert(ok);
+ UNUSED_VARS_NDEBUG(ok);
+ }
+ }
+}
+
+void WM_msg_dump(struct wmMsgBus *mbus, const char *info_str)
+{
+ printf(">>>> %s\n", info_str);
+ for (wmMsgSubscribeKey *key = mbus->messages.first; key; key = key->next) {
+ const wmMsg *msg = wm_msg_subscribe_value_msg_cast(key);
+ const wmMsgTypeInfo *info = &wm_msg_types[msg->type];
+ info->repr(stdout, key);
+ }
+ printf("<<<< %s\n", info_str);
+}
+
+void WM_msgbus_handle(struct wmMsgBus *mbus, struct bContext *C)
+{
+ if (mbus->messages_tag_count == 0) {
+ // printf("msgbus: skipping\n");
+ return;
+ }
+
+ if (false) {
+ WM_msg_dump(mbus, __func__);
+ }
+
+ // uint a = 0, b = 0;
+ for (wmMsgSubscribeKey *key = mbus->messages.first; key; key = key->next) {
+ for (wmMsgSubscribeValueLink *msg_lnk = key->values.first; msg_lnk; msg_lnk = msg_lnk->next) {
+ if (msg_lnk->params.tag) {
+ msg_lnk->params.notify(C, key, &msg_lnk->params);
+ msg_lnk->params.tag = false;
+ mbus->messages_tag_count -= 1;
+ }
+ // b++;
+ }
+ // a++;
+ }
+ BLI_assert(mbus->messages_tag_count == 0);
+ mbus->messages_tag_count = 0;
+ // printf("msgbus: keys=%u values=%u\n", a, b);
+}
+
+/**
+ * \param msg_key_test: Needs following #wmMsgSubscribeKey fields filled in:
+ * - msg.params
+ * - msg.head.type
+ * - msg.head.id
+ * .. other values should be zeroed.
+ *
+ * \return The key for this subscription.
+ * note that this is only needed in rare cases when the key needs further manipulation.
+ */
+wmMsgSubscribeKey *WM_msg_subscribe_with_key(
+ struct wmMsgBus *mbus,
+ const wmMsgSubscribeKey *msg_key_test,
+ const wmMsgSubscribeValue *msg_val_params)
+{
+ const uint type = wm_msg_subscribe_value_msg_cast(msg_key_test)->type;
+ const wmMsgTypeInfo *info = &wm_msg_types[type];
+ wmMsgSubscribeKey *key;
+
+ BLI_assert(wm_msg_subscribe_value_msg_cast(msg_key_test)->id != NULL);
+
+ void **r_key;
+ if (!BLI_gset_ensure_p_ex(mbus->messages_gset[type], msg_key_test, &r_key)) {
+ key = *r_key = MEM_mallocN(info->msg_key_size, __func__);
+ memcpy(key, msg_key_test, info->msg_key_size);
+ BLI_addtail(&mbus->messages, key);
+ }
+ else {
+ key = *r_key;
+ for (wmMsgSubscribeValueLink *msg_lnk = key->values.first; msg_lnk; msg_lnk = msg_lnk->next) {
+ if ((msg_lnk->params.notify == msg_val_params->notify) &&
+ (msg_lnk->params.owner == msg_val_params->owner) &&
+ (msg_lnk->params.user_data == msg_val_params->user_data))
+ {
+ return key;
+ }
+ }
+ }
+
+ wmMsgSubscribeValueLink *msg_lnk = MEM_mallocN(sizeof(wmMsgSubscribeValueLink), __func__);
+ msg_lnk->params = *msg_val_params;
+ BLI_addtail(&key->values, msg_lnk);
+ return key;
+}
+
+void WM_msg_publish_with_key(struct wmMsgBus *mbus, wmMsgSubscribeKey *msg_key)
+{
+ for (wmMsgSubscribeValueLink *msg_lnk = msg_key->values.first; msg_lnk; msg_lnk = msg_lnk->next) {
+ if (false) { /* make an option? */
+ msg_lnk->params.notify(NULL, msg_key, &msg_lnk->params);
+ }
+ else {
+ if (msg_lnk->params.tag == false) {
+ msg_lnk->params.tag = true;
+ mbus->messages_tag_count += 1;
+ }
+ }
+ }
+}
+
+void WM_msg_id_update(
+ struct wmMsgBus *mbus,
+ struct ID *id_src, struct ID *id_dst)
+{
+ for (uint i = 0; i < WM_MSG_TYPE_NUM; i++) {
+ wmMsgTypeInfo *info = &wm_msg_types[i];
+ if (info->update_by_id != NULL) {
+ info->update_by_id(mbus, id_src, id_dst);
+ }
+ }
+}
+
+void WM_msg_id_remove(struct wmMsgBus *mbus, const struct ID *id)
+{
+ for (uint i = 0; i < WM_MSG_TYPE_NUM; i++) {
+ wmMsgTypeInfo *info = &wm_msg_types[i];
+ if (info->remove_by_id != NULL) {
+ info->remove_by_id(mbus, id);
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------------- */
+/** \name Internal API
+ *
+ * \note While we could have a separate type for ID's, use RNA since there is enough overlap.
+ * \{ */
+
+void wm_msg_subscribe_value_free(
+ wmMsgSubscribeKey *msg_key, wmMsgSubscribeValueLink *msg_lnk)
+{
+ if (msg_lnk->params.free_data) {
+ msg_lnk->params.free_data(msg_key, &msg_lnk->params);
+ }
+ BLI_remlink(&msg_key->values, msg_lnk);
+ MEM_freeN(msg_lnk);
+}
+
+/** \} */
diff --git a/source/blender/windowmanager/message_bus/intern/wm_message_bus_intern.h b/source/blender/windowmanager/message_bus/intern/wm_message_bus_intern.h
new file mode 100644
index 00000000000..db8b481a3c2
--- /dev/null
+++ b/source/blender/windowmanager/message_bus/intern/wm_message_bus_intern.h
@@ -0,0 +1,55 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/message_bus/intern/wm_message_bus_intern.h
+ * \ingroup wm
+ */
+
+#ifndef __WM_MESSAGE_BUS_INTERN_H__
+#define __WM_MESSAGE_BUS_INTERN_H__
+
+/* wm_message_bus.h must be included first */
+
+struct wmMsgBus {
+ struct GSet *messages_gset[WM_MSG_TYPE_NUM];
+ /** Messages in order of being added. */
+ ListBase messages;
+ /** Avoid checking messages when no tags exist. */
+ uint messages_tag_count;
+};
+
+void wm_msg_subscribe_value_free(
+ struct wmMsgSubscribeKey *msg_key, struct wmMsgSubscribeValueLink *msg_lnk);
+
+typedef struct wmMsgSubscribeKey_Generic {
+ wmMsgSubscribeKey head;
+ wmMsg msg;
+} wmMsgSubscribeKey_Generic;
+
+BLI_INLINE const wmMsg *wm_msg_subscribe_value_msg_cast(const wmMsgSubscribeKey *key)
+{
+ return &((wmMsgSubscribeKey_Generic *)key)->msg;
+}
+BLI_INLINE wmMsg *wm_msg_subscribe_value_msg_cast_mut(wmMsgSubscribeKey *key)
+{
+ return &((wmMsgSubscribeKey_Generic *)key)->msg;
+}
+
+#endif /* __WM_MESSAGE_BUS_INTERN_H__ */
diff --git a/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c b/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c
new file mode 100644
index 00000000000..f9d8d968b84
--- /dev/null
+++ b/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c
@@ -0,0 +1,316 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/intern/wm_message_bus_rna.c
+ * \ingroup wm
+ */
+
+#include <stdio.h>
+#include "DNA_ID.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+#include "BLI_listbase.h"
+
+#include "WM_types.h"
+#include "WM_message.h"
+#include "message_bus/intern/wm_message_bus_intern.h"
+
+#include "RNA_access.h"
+
+#include "MEM_guardedalloc.h"
+
+/* -------------------------------------------------------------------------- */
+
+BLI_INLINE uint void_hash_uint(const void *key)
+{
+ size_t y = (size_t)key >> (sizeof(void *));
+ return (unsigned int)y;
+}
+
+static uint wm_msg_rna_gset_hash(const void *key_p)
+{
+ const wmMsgSubscribeKey_RNA *key = key_p;
+ const wmMsgParams_RNA *params = &key->msg.params;
+// printf("%s\n", RNA_struct_identifier(params->ptr.type));
+ uint k = void_hash_uint(params->ptr.type);
+ k ^= void_hash_uint(params->ptr.data);
+ k ^= void_hash_uint(params->ptr.id.data);
+ k ^= void_hash_uint(params->prop);
+ return k;
+}
+static bool wm_msg_rna_gset_cmp(const void *key_a_p, const void *key_b_p)
+{
+ const wmMsgParams_RNA *params_a = &((const wmMsgSubscribeKey_RNA *)key_a_p)->msg.params;
+ const wmMsgParams_RNA *params_b = &((const wmMsgSubscribeKey_RNA *)key_b_p)->msg.params;
+ return !(
+ (params_a->ptr.type ==
+ params_b->ptr.type) &&
+ (params_a->ptr.id.data ==
+ params_b->ptr.id.data) &&
+ (params_a->ptr.data ==
+ params_b->ptr.data) &&
+ (params_a->prop ==
+ params_b->prop)
+ );
+}
+static void wm_msg_rna_gset_key_free(void *key_p)
+{
+ wmMsgSubscribeKey_RNA *key = key_p;
+ wmMsgSubscribeValueLink *msg_lnk_next;
+ for (wmMsgSubscribeValueLink *msg_lnk = key->head.values.first; msg_lnk; msg_lnk = msg_lnk_next) {
+ msg_lnk_next = msg_lnk->next;
+ wm_msg_subscribe_value_free(&key->head, msg_lnk);
+ }
+ if (key->msg.params.data_path != NULL) {
+ MEM_freeN(key->msg.params.data_path);
+ }
+ MEM_freeN(key);
+}
+
+static void wm_msg_rna_repr(FILE *stream, const wmMsgSubscribeKey *msg_key)
+{
+ const wmMsgSubscribeKey_RNA *m = (wmMsgSubscribeKey_RNA *)msg_key;
+ const char *none = "<none>";
+ fprintf(stream,
+ "<wmMsg_RNA %p, "
+ "id='%s', "
+ "%s.%s values_len=%d\n",
+ m, m->msg.head.id,
+ m->msg.params.ptr.type ? RNA_struct_identifier(m->msg.params.ptr.type) : none,
+ m->msg.params.prop ? RNA_property_identifier((PropertyRNA *)m->msg.params.prop) : none,
+ BLI_listbase_count(&m->head.values));
+}
+
+static void wm_msg_rna_update_by_id(
+ struct wmMsgBus *mbus,
+ ID *id_src, ID *id_dst)
+{
+ GSet *gs = mbus->messages_gset[WM_MSG_TYPE_RNA];
+ GSetIterator gs_iter;
+ BLI_gsetIterator_init(&gs_iter, gs);
+ while (BLI_gsetIterator_done(&gs_iter) == false) {
+ wmMsgSubscribeKey_RNA *key = BLI_gsetIterator_getKey(&gs_iter);
+ BLI_gsetIterator_step(&gs_iter);
+ if (key->msg.params.ptr.id.data == id_src) {
+
+ /* GSet always needs updating since the key changes. */
+ BLI_gset_remove(gs, key, NULL);
+
+ /* Remove any non-persistent values, so a single persistent
+ * value doesn't modify behavior for the rest. */
+ wmMsgSubscribeValueLink *msg_lnk_next;
+ for (wmMsgSubscribeValueLink *msg_lnk = key->head.values.first; msg_lnk; msg_lnk = msg_lnk_next) {
+ msg_lnk_next = msg_lnk->next;
+ if (msg_lnk->params.is_persistent == false) {
+ wm_msg_subscribe_value_free(&key->head, msg_lnk);
+ }
+ }
+
+ bool remove = true;
+
+ if (BLI_listbase_is_empty(&key->head.values)) {
+ /* Remove, no reason to keep. */
+ }
+ else if (key->msg.params.ptr.data == key->msg.params.ptr.id.data) {
+ /* Simple, just update the ID. */
+ key->msg.params.ptr.data = id_dst;
+ key->msg.params.ptr.id.data = id_dst;
+ remove = false;
+ }
+ else {
+ /* we need to resolve this from the */
+ PointerRNA idptr;
+ RNA_id_pointer_create(id_dst, &idptr);
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ if (!RNA_path_resolve(&idptr, key->msg.params.data_path, &ptr, &prop)) {
+ key->msg.params.ptr = ptr;
+ key->msg.params.prop = prop;
+ remove = false;
+ }
+ }
+
+ printf("AAA ~ %d\n", remove);
+ if (remove) {
+ /* Failed to persist, remove the key. */
+ BLI_remlink(&mbus->messages, key);
+ wm_msg_rna_gset_key_free(key);
+ }
+ else {
+ /* note that it's not impossible this key exists, however it is very unlikely
+ * since a subscriber would need to register in the middle of an undo for eg. so assert for now. */
+ BLI_assert(!BLI_gset_haskey(gs, key));
+ BLI_gset_add(gs, key);
+ }
+ }
+ }
+}
+
+static void wm_msg_rna_remove_by_id(struct wmMsgBus *mbus, const ID *id)
+{
+ GSet *gs = mbus->messages_gset[WM_MSG_TYPE_RNA];
+ GSetIterator gs_iter;
+ BLI_gsetIterator_init(&gs_iter, gs);
+ while (BLI_gsetIterator_done(&gs_iter) == false) {
+ wmMsgSubscribeKey_RNA *key = BLI_gsetIterator_getKey(&gs_iter);
+ BLI_gsetIterator_step(&gs_iter);
+ if (key->msg.params.ptr.id.data == id) {
+ BLI_remlink(&mbus->messages, key);
+ BLI_gset_remove(gs, key, NULL);
+ wm_msg_rna_gset_key_free(key);
+ }
+ }
+}
+
+void WM_msgtypeinfo_init_rna(wmMsgTypeInfo *msgtype_info)
+{
+ msgtype_info->gset.hash_fn = wm_msg_rna_gset_hash;
+ msgtype_info->gset.cmp_fn = wm_msg_rna_gset_cmp;
+ msgtype_info->gset.key_free_fn = wm_msg_rna_gset_key_free;
+
+ msgtype_info->repr = wm_msg_rna_repr;
+ msgtype_info->update_by_id = wm_msg_rna_update_by_id;
+ msgtype_info->remove_by_id = wm_msg_rna_remove_by_id;
+
+ msgtype_info->msg_key_size = sizeof(wmMsgSubscribeKey_RNA);
+}
+
+/* -------------------------------------------------------------------------- */
+
+
+wmMsgSubscribeKey_RNA *WM_msg_lookup_rna(struct wmMsgBus *mbus, const wmMsgParams_RNA *msg_key_params)
+{
+ wmMsgSubscribeKey_RNA key_test;
+ key_test.msg.params = *msg_key_params;
+ return BLI_gset_lookup(mbus->messages_gset[WM_MSG_TYPE_RNA], &key_test);
+}
+
+void WM_msg_publish_rna_params(struct wmMsgBus *mbus, const wmMsgParams_RNA *msg_key_params)
+{
+ wmMsgSubscribeKey_RNA *key;
+
+ if ((key = WM_msg_lookup_rna(mbus, msg_key_params))) {
+ WM_msg_publish_with_key(mbus, &key->head);
+ }
+
+ /* Support anonymous subscribers, this may be some extra overhead
+ * but we want to be able to be more ambiguous. */
+ if (msg_key_params->ptr.id.data || msg_key_params->ptr.data) {
+ wmMsgParams_RNA msg_key_params_anon = *msg_key_params;
+
+ /* We might want to enable this later? */
+ if (msg_key_params_anon.prop != NULL) {
+ /* All properties for this type. */
+ msg_key_params_anon.prop = NULL;
+ if ((key = WM_msg_lookup_rna(mbus, &msg_key_params_anon))) {
+ WM_msg_publish_with_key(mbus, &key->head);
+ }
+ msg_key_params_anon.prop = msg_key_params->prop;
+ }
+
+ msg_key_params_anon.ptr.id.data = NULL;
+ msg_key_params_anon.ptr.data = NULL;
+ if ((key = WM_msg_lookup_rna(mbus, &msg_key_params_anon))) {
+ WM_msg_publish_with_key(mbus, &key->head);
+ }
+
+ /* Support subscribers to a type. */
+ if (msg_key_params->prop) {
+ msg_key_params_anon.prop = NULL;
+ if ((key = WM_msg_lookup_rna(mbus, &msg_key_params_anon))) {
+ WM_msg_publish_with_key(mbus, &key->head);
+ }
+ }
+ }
+}
+
+void WM_msg_publish_rna(struct wmMsgBus *mbus, PointerRNA *ptr, PropertyRNA *prop)
+{
+ WM_msg_publish_rna_params(mbus, &(wmMsgParams_RNA){ .ptr = *ptr, .prop = prop, });
+}
+
+void WM_msg_subscribe_rna_params(
+ struct wmMsgBus *mbus,
+ const wmMsgParams_RNA *msg_key_params,
+ const wmMsgSubscribeValue *msg_val_params,
+ const char *id_repr)
+{
+ wmMsgSubscribeKey_RNA msg_key_test = {{NULL}};
+
+ /* use when added */
+ msg_key_test.msg.head.id = id_repr;
+ msg_key_test.msg.head.type = WM_MSG_TYPE_RNA;
+ /* for lookup */
+ msg_key_test.msg.params = *msg_key_params;
+
+ wmMsgSubscribeKey_RNA *msg_key = (wmMsgSubscribeKey_RNA *)WM_msg_subscribe_with_key(
+ mbus, &msg_key_test.head, msg_val_params);
+
+ if (msg_val_params->is_persistent) {
+ if (msg_key->msg.params.data_path == NULL) {
+ if (msg_key->msg.params.ptr.data != msg_key->msg.params.ptr.id.data) {
+ /* We assume prop type can't change. */
+ msg_key->msg.params.data_path = RNA_path_from_ID_to_struct(&msg_key->msg.params.ptr);
+ }
+ }
+ }
+}
+
+void WM_msg_subscribe_rna(
+ struct wmMsgBus *mbus,
+ PointerRNA *ptr, const PropertyRNA *prop,
+ const wmMsgSubscribeValue *msg_val_params,
+ const char *id_repr)
+{
+ WM_msg_subscribe_rna_params(
+ mbus,
+ &(const wmMsgParams_RNA){
+ .ptr = *ptr,
+ .prop = prop,
+ },
+ msg_val_params, id_repr);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------------- */
+/** \name ID variants of RNA API
+ *
+ * \note While we could have a separate type for ID's, use RNA since there is enough overlap.
+ * \{ */
+
+void WM_msg_subscribe_ID(
+ struct wmMsgBus *mbus, ID *id, const wmMsgSubscribeValue *msg_val_params,
+ const char *id_repr)
+{
+ wmMsgParams_RNA msg_key_params = {NULL};
+ RNA_id_pointer_create(id, &msg_key_params.ptr);
+ WM_msg_subscribe_rna_params(mbus, &msg_key_params, msg_val_params, id_repr);
+}
+
+void WM_msg_publish_ID(struct wmMsgBus *mbus, ID *id)
+{
+ wmMsgParams_RNA msg_key_params = {NULL};
+ RNA_id_pointer_create(id, &msg_key_params.ptr);
+ WM_msg_publish_rna_params(mbus, &msg_key_params);
+}
+
+/** \} */
diff --git a/source/blender/windowmanager/message_bus/intern/wm_message_bus_static.c b/source/blender/windowmanager/message_bus/intern/wm_message_bus_static.c
new file mode 100644
index 00000000000..59bebad7f7b
--- /dev/null
+++ b/source/blender/windowmanager/message_bus/intern/wm_message_bus_static.c
@@ -0,0 +1,136 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/intern/wm_message_bus_static.c
+ * \ingroup wm
+ */
+
+#include <stdio.h>
+
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+#include "BLI_listbase.h"
+
+#include "WM_types.h"
+#include "WM_message.h"
+#include "message_bus/intern/wm_message_bus_intern.h"
+
+#include "MEM_guardedalloc.h"
+
+/* -------------------------------------------------------------------------- */
+
+static uint wm_msg_static_gset_hash(const void *key_p)
+{
+ const wmMsgSubscribeKey_Static *key = key_p;
+ const wmMsgParams_Static *params = &key->msg.params;
+ uint k = params->event;
+ return k;
+}
+static bool wm_msg_static_gset_cmp(const void *key_a_p, const void *key_b_p)
+{
+ const wmMsgParams_Static *params_a = &((const wmMsgSubscribeKey_Static *)key_a_p)->msg.params;
+ const wmMsgParams_Static *params_b = &((const wmMsgSubscribeKey_Static *)key_b_p)->msg.params;
+ return !(
+ (params_a->event ==
+ params_b->event)
+ );
+}
+static void wm_msg_static_gset_key_free(void *key_p)
+{
+ wmMsgSubscribeKey *key = key_p;
+ wmMsgSubscribeValueLink *msg_lnk_next;
+ for (wmMsgSubscribeValueLink *msg_lnk = key->values.first; msg_lnk; msg_lnk = msg_lnk_next) {
+ msg_lnk_next = msg_lnk->next;
+ BLI_remlink(&key->values, msg_lnk);
+ MEM_freeN(msg_lnk);
+ }
+ MEM_freeN(key);
+}
+
+static void wm_msg_static_repr(FILE *stream, const wmMsgSubscribeKey *msg_key)
+{
+ const wmMsgSubscribeKey_Static *m = (wmMsgSubscribeKey_Static *)msg_key;
+ fprintf(stream,
+ "<wmMsg_Static %p, "
+ "id='%s', "
+ "values_len=%d\n",
+ m, m->msg.head.id,
+ BLI_listbase_count(&m->head.values));
+}
+
+
+void WM_msgtypeinfo_init_static(wmMsgTypeInfo *msgtype_info)
+{
+ msgtype_info->gset.hash_fn = wm_msg_static_gset_hash;
+ msgtype_info->gset.cmp_fn = wm_msg_static_gset_cmp;
+ msgtype_info->gset.key_free_fn = wm_msg_static_gset_key_free;
+ msgtype_info->repr = wm_msg_static_repr;
+
+ msgtype_info->msg_key_size = sizeof(wmMsgSubscribeKey_Static);
+}
+
+/* -------------------------------------------------------------------------- */
+
+
+wmMsgSubscribeKey_Static *WM_msg_lookup_static(struct wmMsgBus *mbus, const wmMsgParams_Static *msg_key_params)
+{
+ wmMsgSubscribeKey_Static key_test;
+ key_test.msg.params = *msg_key_params;
+ return BLI_gset_lookup(mbus->messages_gset[WM_MSG_TYPE_STATIC], &key_test);
+}
+
+void WM_msg_publish_static_params(struct wmMsgBus *mbus, const wmMsgParams_Static *msg_key_params)
+{
+ wmMsgSubscribeKey_Static *key = WM_msg_lookup_static(mbus, msg_key_params);
+ if (key) {
+ WM_msg_publish_with_key(mbus, &key->head);
+ }
+}
+
+void WM_msg_publish_static(struct wmMsgBus *mbus, int event)
+{
+ WM_msg_publish_static_params(mbus, &(wmMsgParams_Static){ .event = event, });
+}
+
+void WM_msg_subscribe_static_params(
+ struct wmMsgBus *mbus,
+ const wmMsgParams_Static *msg_key_params,
+ const wmMsgSubscribeValue *msg_val_params,
+ const char *id_repr)
+{
+ wmMsgSubscribeKey_Static msg_key_test = {{NULL}};
+
+ /* use when added */
+ msg_key_test.msg.head.id = id_repr;
+ msg_key_test.msg.head.type = WM_MSG_TYPE_STATIC;
+ /* for lookup */
+ msg_key_test.msg.params = *msg_key_params;
+
+ WM_msg_subscribe_with_key(mbus, &msg_key_test.head, msg_val_params);
+}
+
+void WM_msg_subscribe_static(
+ struct wmMsgBus *mbus,
+ int event,
+ const wmMsgSubscribeValue *msg_val_params,
+ const char *id_repr)
+{
+ WM_msg_subscribe_static_params(mbus, &(const wmMsgParams_Static){ .event = event, }, msg_val_params, id_repr);
+}
diff --git a/source/blender/windowmanager/message_bus/wm_message_bus.h b/source/blender/windowmanager/message_bus/wm_message_bus.h
new file mode 100644
index 00000000000..53f283cacd2
--- /dev/null
+++ b/source/blender/windowmanager/message_bus/wm_message_bus.h
@@ -0,0 +1,256 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/wm_message_bus.h
+ * \ingroup wm
+ */
+
+#ifndef __WM_MESSAGE_BUS_H__
+#define __WM_MESSAGE_BUS_H__
+
+struct GSet;
+struct ID;
+struct bContext;
+struct wmMsg;
+
+/* opaque (don't expose outside wm_message_bus.c) */
+struct wmMsgBus;
+struct wmMsgSubscribeKey;
+struct wmMsgSubscribeValue;
+struct wmMsgSubscribeValueLink;
+
+typedef void (*wmMsgNotifyFn)(
+ struct bContext *C, struct wmMsgSubscribeKey *msg_key, struct wmMsgSubscribeValue *msg_val);
+typedef void (*wmMsgSubscribeValueFreeDataFn)(
+ struct wmMsgSubscribeKey *msg_key, struct wmMsgSubscribeValue *msg_val);
+
+/* Exactly what arguments here is not obvious. */
+typedef void (*wmMsgSubscribeValueUpdateIdFn)(
+ struct bContext *C,
+ struct wmMsgBus *mbus,
+ struct ID *id_src, struct ID *id_dst,
+ struct wmMsgSubscribeValue *msg_val);
+enum {
+ WM_MSG_TYPE_RNA = 0,
+ WM_MSG_TYPE_STATIC = 1,
+};
+#define WM_MSG_TYPE_NUM 2
+
+typedef struct wmMsgTypeInfo {
+ struct {
+ unsigned int (*hash_fn)(const void *msg);
+ bool (*cmp_fn)(const void *a, const void *b);
+ void (*key_free_fn)(void *key);
+ } gset;
+
+ void (*update_by_id)(struct wmMsgBus *mbus, struct ID *id_src, struct ID *id_dst);
+ void (*remove_by_id)(struct wmMsgBus *mbus, const struct ID *id);
+ void (*repr)(FILE *stream, const struct wmMsgSubscribeKey *msg_key);
+
+ /* sizeof(wmMsgSubscribeKey_*) */
+ uint msg_key_size;
+} wmMsgTypeInfo;
+
+typedef struct wmMsg {
+ unsigned int type;
+// #ifdef DEBUG
+ /* For debugging: '__func__:__LINE__'. */
+ const char *id;
+// #endif
+} wmMsg;
+
+typedef struct wmMsgSubscribeKey {
+ /** Linked list for predicable ordering, otherwise we would depend on ghash bucketing. */
+ struct wmMsgSubscribeKey *next, *prev;
+ ListBase values;
+ /* over-alloc, eg: wmMsgSubscribeKey_RNA */
+ /* Last member will be 'wmMsg_*' */
+} wmMsgSubscribeKey;
+
+/** One of many in #wmMsgSubscribeKey.values */
+typedef struct wmMsgSubscribeValue {
+ struct wmMsgSubscribe *next, *prev;
+
+ /** Handle, used to iterate and clear. */
+ void *owner;
+ /** User data, can be whatever we like, free using the 'free_data' callback if it's owned. */
+ void *user_data;
+
+ /** Callbacks */
+ wmMsgNotifyFn notify;
+ wmMsgSubscribeValueUpdateIdFn update_id;
+ wmMsgSubscribeValueFreeDataFn free_data;
+
+ /** Keep this subscriber if possible. */
+ uint is_persistent : 1;
+ /* tag to run when handling events,
+ * we may want option for immediate execution. */
+ uint tag : 1;
+} wmMsgSubscribeValue;
+
+/** One of many in #wmMsgSubscribeKey.values */
+typedef struct wmMsgSubscribeValueLink {
+ struct wmMsgSubscribeValueLink *next, *prev;
+ wmMsgSubscribeValue params;
+} wmMsgSubscribeValueLink;
+
+void WM_msgbus_types_init(void);
+
+struct wmMsgBus *WM_msgbus_create(void);
+void WM_msgbus_destroy(struct wmMsgBus *mbus);
+
+void WM_msgbus_clear_by_owner(struct wmMsgBus *mbus, void *owner);
+
+void WM_msg_dump(struct wmMsgBus *mbus, const char *info);
+void WM_msgbus_handle(struct wmMsgBus *mbus, struct bContext *C);
+
+void WM_msg_publish_with_key(struct wmMsgBus *mbus, wmMsgSubscribeKey *msg_key);
+wmMsgSubscribeKey *WM_msg_subscribe_with_key(
+ struct wmMsgBus *mbus,
+ const wmMsgSubscribeKey *msg_key_test,
+ const wmMsgSubscribeValue *msg_val_params);
+
+void WM_msg_id_update(
+ struct wmMsgBus *mbus,
+ struct ID *id_src, struct ID *id_dst);
+void WM_msg_id_remove(struct wmMsgBus *mbus, const struct ID *id);
+
+/* -------------------------------------------------------------------------- */
+/* wm_message_bus_static.c */
+
+enum {
+ /* generic window redraw */
+ WM_MSG_STATICTYPE_WINDOW_DRAW = 0,
+ WM_MSG_STATICTYPE_SCREEN_EDIT = 1,
+ WM_MSG_STATICTYPE_FILE_READ = 2,
+};
+
+typedef struct wmMsgParams_Static {
+ int event;
+} wmMsgParams_Static;
+
+typedef struct wmMsg_Static {
+ wmMsg head; /* keep first */
+ wmMsgParams_Static params;
+} wmMsg_Static;
+
+typedef struct wmMsgSubscribeKey_Static {
+ wmMsgSubscribeKey head;
+ wmMsg_Static msg;
+} wmMsgSubscribeKey_Static;
+
+void WM_msgtypeinfo_init_static(wmMsgTypeInfo *msg_type);
+
+wmMsgSubscribeKey_Static *WM_msg_lookup_static(
+ struct wmMsgBus *mbus, const wmMsgParams_Static *msg_key_params);
+void WM_msg_publish_static_params(
+ struct wmMsgBus *mbus,
+ const wmMsgParams_Static *msg_key_params);
+void WM_msg_publish_static(
+ struct wmMsgBus *mbus,
+ /* wmMsgParams_Static (expanded) */
+ int event);
+void WM_msg_subscribe_static_params(
+ struct wmMsgBus *mbus,
+ const wmMsgParams_Static *msg_key_params,
+ const wmMsgSubscribeValue *msg_val_params,
+ const char *id_repr);
+void WM_msg_subscribe_static(
+ struct wmMsgBus *mbus,
+ int event,
+ const wmMsgSubscribeValue *msg_val_params,
+ const char *id_repr);
+
+/* -------------------------------------------------------------------------- */
+/* wm_message_bus_rna.c */
+
+typedef struct wmMsgParams_RNA {
+ /** when #PointerRNA.data & id.data are NULL. match against all. */
+ PointerRNA ptr;
+ /** when NULL, match against any property. */
+ const PropertyRNA *prop;
+
+ /**
+ * Optional RNA data path for persistent RNA properties, ignore if NULL.
+ * otherwise it's allocated.
+ */
+ char *data_path;
+} wmMsgParams_RNA;
+
+typedef struct wmMsg_RNA {
+ wmMsg head; /* keep first */
+ wmMsgParams_RNA params;
+} wmMsg_RNA;
+
+typedef struct wmMsgSubscribeKey_RNA {
+ wmMsgSubscribeKey head;
+ wmMsg_RNA msg;
+} wmMsgSubscribeKey_RNA;
+
+void WM_msgtypeinfo_init_rna(wmMsgTypeInfo *msg_type);
+
+wmMsgSubscribeKey_RNA *WM_msg_lookup_rna(
+ struct wmMsgBus *mbus, const wmMsgParams_RNA *msg_key_params);
+void WM_msg_publish_rna_params(
+ struct wmMsgBus *mbus, const wmMsgParams_RNA *msg_key_params);
+void WM_msg_publish_rna(
+ struct wmMsgBus *mbus,
+ /* wmMsgParams_RNA (expanded) */
+ PointerRNA *ptr, PropertyRNA *prop);
+void WM_msg_subscribe_rna_params(
+ struct wmMsgBus *mbus,
+ const wmMsgParams_RNA *msg_key_params,
+ const wmMsgSubscribeValue *msg_val_params,
+ const char *id_repr);
+void WM_msg_subscribe_rna(
+ struct wmMsgBus *mbus,
+ PointerRNA *ptr, const PropertyRNA *prop,
+ const wmMsgSubscribeValue *msg_val_params,
+ const char *id_repr);
+
+/* ID variants */
+void WM_msg_subscribe_ID(
+ struct wmMsgBus *mbus, struct ID *id, const wmMsgSubscribeValue *msg_val_params,
+ const char *id_repr);
+void WM_msg_publish_ID(
+ struct wmMsgBus *mbus, struct ID *id);
+
+/* Anonymous variants (for convenience) */
+#define WM_msg_subscribe_rna_anon_type(mbus, type_, value) { \
+ WM_msg_subscribe_rna_params( \
+ mbus, \
+ &(const wmMsgParams_RNA){ \
+ .ptr = (PointerRNA){.type = &RNA_##type_}, \
+ .prop = NULL, \
+ }, \
+ value, __func__); \
+} ((void)0)
+#define WM_msg_subscribe_rna_anon_prop(mbus, type_, prop_, value) { \
+ extern PropertyRNA rna_##type_##_##prop_; \
+ WM_msg_subscribe_rna_params( \
+ mbus, \
+ &(const wmMsgParams_RNA){ \
+ .ptr = (PointerRNA){.type = &RNA_##type_}, \
+ .prop = &rna_##type_##_##prop_, \
+ }, \
+ value, __func__); \
+} ((void)0)
+
+#endif /* __WM_MESSAGE_BUS_H__ */